【发布时间】:2020-08-06 00:55:59
【问题描述】:
根据我构造 Log 对象的方式,我收到一个编译器错误,指出我正在尝试引用已删除的函数(复制构造函数):
C:\Projects\Logger\src\Logger.cpp(34,1): 错误 C2280: 'Logger::Log::Log(const Logger::Log &)': 试图引用已删除的函数 [C :\Projects\Logger\build\Logger.vcxproj]
我的 Log 对象应该有 implicitly deleted 复制构造函数,因为:
T 具有无法复制的非静态数据成员(已删除、不可访问或不明确的复制构造函数);
这是有道理的,因为std::ofstream 有其copy constructor deleted。
我不明白为什么要调用复制构造函数。使用调用复制构造函数的赋值运算符进行构造是什么?我正在使用 MSVC 进行编译,是否有一些我没有使用的编译器标志不能优化某些行为?例如。构造临时对象,然后将构造复制到命名对象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;
}
类接口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;
}
};
}
【问题讨论】:
-
能看到类界面吗?它可能会有所帮助
-
添加类接口
-
Logger::Log foo = Logger::Log::Log("sample.log")语义上(在 C++17 之前)使用字符串创建一个临时的Logger::Log,然后使用复制构造函数用该临时值初始化foo- 即使编译器省略该副本需要诊断复制构造函数的语义使用。从 C++17 开始,临时文件将被省略。在 C++17 之前,修复方法是将定义更改为Logger::Log foo ("sample.log") -
@Peter 应该作为答案发布。
标签: c++