提问人:Caiyi Zhou 提问时间:3/1/2021 更新时间:3/1/2021 访问量:219
为什么删除 templete copy 构造函数会导致赋值运算符失灵?
Why delete of templete copy constructor cause assignment operator disfunctional?
问:
我有如下代码,看起来有点令人困惑。我定义了一个模板类。它有一个用户定义的构造函数。当我通过“operator =”声明这个模板类的两个对象时,它的用户定义的构造器被调用,这让我感到惊讶。此外,删除其复制构造函数后,编译甚至无法在解析“operator =”期间通过。templete 构造函数的规则是否与非 templete 类不同?
#include "iostream"
using namespace std;
template <typename T>
class MyPtr
{
private:
T p_;
public:
MyPtr(T P = NULL): p_(P)
{
cout<<"track!!"<<endl;
}
//MyPtr(const MyPtr<T> & P) = delete;
~MyPtr()
{
}
};
int main()
{
int i=3;
int j=4;
MyPtr<int> p = i;
MyPtr<int> pp = j;
}
答:
4赞
songyuanyao
3/1/2021
#1
templete 构造函数的规则是否与非 templete 类不同?
不。
MyPtr<int> p = i;
(和 ) 是复制初始化。请注意,这是初始化,但不是赋值,因为效果是由构造函数初始化的。例如:MyPtr<int> pp = j;
p
MyPtr::MyPtr(T)
MyPtr<int> p = i; // initialization; constructors get called
p = j; // assignment; assignment operators (operator=) get called
在C++17之前,会先转换为via,然后转换结果,即临时被复制/移动初始化;即使允许优化复制/移动操作,复制/移动构造函数也需要可访问。将复制构造函数声明为会使复制构造函数不可用,并且不会生成移动构造函数,因此在 C++17 之前格式不正确。i
MyPtr<int>
MyPtr::MyPtr(T)
MyPtr<int>
p
delete
MyPtr<int> p = i;
由于 C++17 优化是必需的,并且不需要再次访问复制/移动构造函数,这意味着您的代码甚至可以在 C++17 模式下正常编译,甚至将复制构造函数声明为 。delete
- 如果 T 是类类型,并且 other 类型的 cv 非限定版本不是 T 或派生自 T,或者如果 T 是非类类型,但 other 的类型是类类型,则检查可以从 other 类型转换为 T 的用户定义的转换序列(如果 T 是类类型并且转换函数可用,则转换为从 T 派生的类型)并找到最佳通过重载分辨率进行选择。转换结果(如果使用了转换构造函数)将用于直接初始化对象。
prvalue temporary (until C++17)
prvalue expression (since C++17)
The last step is usually optimized out and the result of the conversion is constructed directly in the memory allocated for the target object, but the appropriate constructor (move or copy) is required to be accessible even though it's not used. (until C++17)
评论
MyPtr<int> p = i
调用复制构造函数: en.cppreference.com/w/cpp/language/copy_constructor “每当一个对象从相同类型的另一个对象初始化(通过直接初始化或复制初始化)时,都会调用复制构造函数(除非重载解析选择更好的匹配或省略调用),其中包括初始化:T a = b;
或 Ta(b)
;,其中b
为T
型;“这意味着隐式转换为利用,然后调用复制构造函数(或至少它必须存在)(直到C++17)。i
MyPtr<int>
MyPtr(T P = NULL)