[英]What is referencing the copy constructor?
根據我構建Log
object 的方式,我收到一個編譯器錯誤,指出我正在嘗試引用已刪除的 function(復制構造函數):
C:\Projects\Logger\src\Logger.cpp(34,1):錯誤 C2280:'Logger::Log::Log(const Logger::Log &)':試圖引用已刪除的 function [C:\Projects \Logger\build\Logger.vcxproj]
預計我的日志 object 已隱式刪除了復制構造函數,因為:
T 具有無法復制的非靜態數據成員(已刪除、不可訪問或不明確的復制構造函數);
這是有道理的,因為std::ofstream
的 復制構造函數已刪除。
我無法弄清楚為什么要調用復制構造函數。 使用調用復制構造函數的賦值運算符進行構造是什么? 我正在使用 MSVC 進行編譯,是否有一些我沒有使用的編譯器標志不能優化某些行為? 例如構造臨時 object 然后將構造復制到命名的 object foo
?
如下代碼塊所示,只有一個構造函數定義。
#include <iostream>
#include <string>
#include <fstream>
#include "Logger.h"
#include "LoggerConfig.h"
Logger::Log::Log(std::string file) : filename{ file }
{
logFile = std::ofstream(filename, std::ios::out);
if (logFile.is_open())
{
logFile << "This is a log.\n";
}
else
{
std::cout << "Unable to open filename: " << filename << '\n';
}
}
Logger::Log::~Log()
{
// Wait and take write mutex
// Close file
}
int main()
{
// report version
std::cout << " Version " << LOGGER_VERSION_MAJOR << "."
<< LOGGER_VERSION_MINOR << std::endl;
Logger::Log foo = Logger::Log::Log("sample.log"); // C2280: attemping to reference a deleted function
//Logger::Log foo("sample.log"); // Works!
//Logger::Log foo{"sample.log"}; // Works!
foo.Write(Logger::Log::Level::INFO, "Testing", 123, "hahaha");
return 0;
}
Class接口logger.h如下:
#pragma once
namespace Logger
{
class Log
{
private:
std::string filename;
std::ofstream logFile;
public:
enum class Level
{
DEBUG,
INFO,
WARNING,
ERROR
};
Log(std::string file);
~Log();
template<typename T>
void Write(Level lvl, T arg)
{
logFile << arg;
return;
}
template<typename T, typename... Args>
void Write(Level lvl, T firstArg, Args... args)
{
logFile << firstArg;
Write(lvl, args...);
return;
}
};
}
這不僅僅是關於不必要的副本和 C++17,我們知道
Logger::Log foo("sample.log");
工作正常,但為什么這會標記 C2280 錯誤
Logger::Log foo = Logger::Log::Log("sample.log");
問題出在 class 中的 ofstream 中,我得到了你的代碼並編譯了它,我對 ofstream object 有疑問,我刪除了它,它也可以正常工作,我將它設為指針也可以正常工作,然后我嘗試了這個代碼:
std::ofstream s = std::ofstream("sample.log", std::ios::out);
std::ofstream k;
k = s;
我收到此錯誤 E1776 function “std::basic_ofstream<_Elem, _Traits>::operator=(const std::basic_ofstream<_Elem, _Traits> &) [with _Elem=char, _Traits=std::char_traits]”(聲明於無法引用“C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.25.28610\include\fstream”的第 1080 行 - 它是已刪除的 function
這意味着 ofstream 阻止復制構造函數和 =operator 以避免訪問相同的數據(文件),當您通過此行調用復制構造函數時,您的代碼就是這種情況
Logger::Log foo = Logger::Log::Log("sample.log");
隱式使用默認復制構造函數,它使用 = 操作符逐個字段復制您擁有的每個 object 或原始類型,ofstream 就是這種情況,它阻止 = 操作符,然后編譯器標記調用已刪除的 function 錯誤 -
要解決這個問題,您可以使用原始指針或智能指針聲明 ofstream 指針並管理 memory 或者您也可以使用您的自定義創建移動構造函數版本——這也將刪除 class 中的默認復制構造函數——並盡量避免使用不同的ofstreams訪問相同的數據。
Logger::Log foo = Logger::Log::Log("sample.log");
此行首先創建一個Log
並將其復制到foo
。
您必須像這樣調用構造函數Logger::Log foo("sample.log")
因為您所做的將創建一個不必要的副本,這是 C++17 之前的編譯器不喜歡的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.