冲突的 CLANG"虚拟 dtor"和"已弃用的复制运算符"警告
Conflicting CLANG `virtual dtor` and `deprecated copy operator` warnings
在我的Qt项目中,我有一个如下所示的类。我收到以下警告(已理解(,并添加一个虚拟 dtor。
dbmappingcomponentaware.h:25: warning: CDbMappingComponentAware has virtual functions but non-virtual destructor
现在我得到
warning: definition of implicit copy assignment operator for 'CDbMappingComponentAware' is deprecated because it has a user-declared destructor
该类是一个普通的香草类,我没有声明任何运算符。我将如何解决这一冲突?
至于如何在有用户定义的析构函数时禁用隐式定义的复制构造函数生成,看起来我必须接受"弃用"警告,但我不确定。
代码片段:
//! Allows subcomponents to gain access to model component
class CDbMappingComponentAware {
public:
//! Destructor (added for 1st warning)
// virtual ~CDbMappingComponentAware() {}
//! Set the corresponding component
virtual void setMappingComponent(CDbMappingComponent *component);
...
...
--根据评论进行编辑 --
读 https://en.cppreference.com/w/cpp/language/copy_assignment 它说,
隐式定义的复制赋值运算符的生成为 已弃用(自 C++11 起(,如果 T 具有用户声明的析构函数或 用户声明的复制构造函数。
但这是为什么呢?我的意思是,为什么 dtor 会影响复制运算符?
至于 如何在有用户定义的析构函数时禁用隐式定义的复制构造函数生成,看起来我必须接受"弃用"警告,但我不确定。
您不必接受"已弃用"警告。这里有 3 个选项,实现运算符、显式默认运算符或删除运算符。
首先,此警告是触发的,因为您实际上在某处使用了copy assignment operator
。甚至可能不是故意的(请参阅以下示例中的//unfortunate mistake
(。除了使用运算符的警告之外,您实际上还应该得到一个注释,例如:
note: in implicit copy assignment operator for 'CDbMappingComponentAware' first required here
请考虑以下示例(运行版本(:
class foo {
public:
virtual ~foo() {}
// options
// implement
//foo& operator=(foo const&) {return *this;}
// default
//foo& operator=(foo const&) = default;
// delete
//foo& operator=(foo const&) = delete;
};
class bar : public foo {
public:
~bar() override {};
};
// stupid mistake... should be defined
// void fn(bar const&)
void fn(bar) {}
int main(int, char*[]) {
foo* f1 = new bar;
foo* f2 = new bar;
// triggers warning
*f1 = *f2;
// unfortunate mistake
bar b;
// triggers warning twice since bar inherits from foo
fn(b);
return 0;
}
在这种情况下,您确实在使用copy assignment operator
,您应该实现它,或者如果它真的是普通的香草,则应默认它。请参阅下面为什么您最终不应该默认它。如果您根本不希望能够复制实例,请删除运算符/ctor。
顺便说一下,复制构造函数也是如此,而不仅仅是赋值运算符。在草案 n4727 中,对于复制构造函数的 §15.8.1/6和对于复制赋值运算符,在§15.8.2/2中对其进行了描述。
然而:
但这是否意味着如果我定义虚拟 dtor,我就无法复制对象(除非我显式编写复制赋值运算符(。
不可以,您仍然可以使用生成的副本 ctor/分配,只要它是警告。弃用意味着它将来(可能(成为一个错误(如果是C++可能在大约 40 年或更长时间内,如果有的话(。因此,如果您不希望您的代码将此警告作为错误吐出,当编译器不再支持它时,您应该立即修复它。
但这是为什么呢?我的意思是,为什么 dtor 会影响复制运算符?
这里的假设答案:
我能想到的一个目的是防止一些错误。考虑这个例子(取自为什么我的构造函数不能正常工作? ):
class Handle {
private:
string name;
X* p;
public:
Handle(string n)
:name(n), p(0) { /* acquire X called "name" and let p point to it */ }
~Handle() { delete p; /* release X called "name" */ }
};
void f(const string& hh)
{
Handle h1(hh);
Handle h2 = h1; // leads to disaster!
}
在这里,默认副本给了我们 h2.name==h1.name 和 h2.p==h1.p。这会导致灾难:当我们退出 f(( 时,h1 和 h2 的析构函数被调用,h1.p 和 h2.p 指向的对象被删除两次。
为了防止双重删除,您必须明确并且不依赖于生成/默认的复制构造函数/赋值。
你是说警告是为了执行三法则吗?
在这种特殊情况下:是的,我会这么说。
由于我不处理资源,因此三法则在这里没有真正的意义。
这将要求编译器考虑成员。对于这样一个不成熟的警告,几乎是很努力的。
个人想法:
恕我直言,我不相信这将成为C++的错误。有很多代码,依赖于自动生成的ctor/赋值。将此错误作为错误会破坏(字面意思(项目。-> 不会发生...
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 使用strcpy将char数组的元素复制到另一个数组
- 是否可以初始化不可复制类型的成员变量(或基类)
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 复制列表初始化的隐式转换的等级是多少
- 当从函数参数中的临时值调用复制构造函数时
- 有可能在Armadillo中复制MATLAB circshift方法吗
- 复制几乎为空的数组的最快方法
- 以下示例中如何避免代码复制?C++/库达
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 文件系统:复制功能的速度秘诀是什么
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 使lambda不可复制/不可移动