c++ - 什么是引用复制构造函数?
问题描述
根据我构造Log
对象的方式,我收到一个编译器错误,指出我正在尝试引用已删除的函数(复制构造函数):
C:\Projects\Logger\src\Logger.cpp(34,1): 错误 C2280: 'Logger::Log::Log(const Logger::Log &)': 试图引用已删除的函数 [C:\Projects \Logger\build\Logger.vcxproj]
预计我的 Log 对象已隐式删除了复制构造函数,因为:
T 具有无法复制的非静态数据成员(已删除、不可访问或不明确的复制构造函数);
这是有道理的,因为std::ofstream
它的复制构造函数已删除。
我无法弄清楚为什么要调用复制构造函数。使用调用复制构造函数的赋值运算符进行构造是什么?我正在使用 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;
}
};
}
解决方案
这不仅仅是关于不必要的副本和 C++17,我们知道
Logger::Log foo("sample.log");
工作正常,但为什么这会标记 C2280 错误
Logger::Log foo = Logger::Log::Log("sample.log");
问题出在类中的 ofstream 中,我得到了你的代码并编译了它,我对 ofstream 对象有疑问,我删除了它,它工作正常我也把它变成了一个指针也工作正常,然后我尝试了这个代码:
std::ofstream s = std::ofstream("sample.log", std::ios::out);
std::ofstream k;
k = s;
我收到此错误 E1776 函数“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 行——这是一个已删除的函数
这意味着 ofstream 阻止复制构造函数和 =operator 以避免访问相同的数据(文件),当您通过此行调用复制构造函数时,您的代码就是这种情况
Logger::Log foo = Logger::Log::Log("sample.log");
隐式使用默认的复制构造函数,它使用 = 运算符为您拥有的每个对象或原始类型逐个字段复制,而 ofstream 就是这种情况,它阻止 = 运算符然后编译器标记为调用已删除的函数错误 -
要解决这个问题,您可以使用原始指针或智能指针声明 ofstream 指针并管理内存,或者您也可以使用自定义创建移动构造函数版本——这也会删除类中的默认复制构造函数——并尽量避免使用不同的ofstreams访问相同的数据。
推荐阅读
- python - 将字符串转换为日期时间作为两行之间截取的结果
- php - PHP:将三个变量(年、月、日)合并为一个日期
- xml - XSLT 空 XML 值删除父结束标记
- git - IntelliJ IDEA 从差异中创建补丁
- php - laravel 上的分页
- angular - 将 Angular 6 升级到 Angular 7 测试版
- angular - 尝试区分“[object Object]”时出错。调用 get 时只允许使用数组和可迭代对象
- regex - 如何判断下一行是否需要缩进?
- javascript - 如何通过 JavaScript 将 PHP 值从一个 PHP 页面传递到另一个 PHP 页面?
- c# - System.Configuration.dll 中发生未处理的异常