我的副本构造函数没有被调用,我不知道为什么。这是我的代码:
template <typename T>
class SmartPtr
{
public:
explicit SmartPtr(T *p) : m_p(p) { cout << "ctor" << endl; }
SmartPtr(const SmartPtr& p) : m_p(p.m_p) { cout << "copy ctor" << endl;}
private:
T* m_p;
};
int main()
{
SmartPtr<int> pt4 = SmartPtr<int>(new int);
}
输出只是“ctor”。它看起来像是使用默认的复制构造函数。如果我添加“显式”然后它不编译,给出错误:
"error: no matching function for call to ‘SmartPtr<int>::SmartPtr(SmartPtr<int>)’"
我在这里做错了什么?
答案 0 :(得分:1)
这就是所谓的Copy Elision。这是一个很好的优化,其中副本显然不是必需的。而不是有效地运行代码:
SmartPtr<int> __tmp(new int);
SmartPtr<int> ptr4(__tmp);
__tmp.~SmartPtr<int>();
编译器可以知道只有__tmp
才能构造ptr4
,因此可以在__tmp
所拥有的内存中就地构建ptr4
好像最初运行的实际代码只是:
SmartPtr<int> ptr4(new int);
请注意,您也可以告诉编译器不要这样做。例如,在gcc上,您可以传递-fno-elide-constructors
选项并进行单个更改(另外记录析构函数),现在代码打印出来:
ctor
copy ctor // not elided!
dtor
dtor // extra SmartPtr!
请参阅demo。
在标准中,§12.8:
在下列情况下(可以合并以消除多份副本),允许复制/移动操作(称为复制省略)的省略:
- 在具有类返回类型的函数的
return
语句中,何时...- 在 throw-expression 中,当......
- 当复制/移动尚未绑定到引用(12.2)的临时类对象时 对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作 将临时对象直接构造到省略的copy / move
的目标中- 当异常处理程序的异常声明(第15条)......
时[示例:的
class Thing { public: Thing(); ~Thing(); Thing(const Thing&); }; Thing f() { Thing t; return t; } Thing t2 = f();
这里可以合并elision的标准,以消除对类
Thing
的复制构造函数的两次调用: 将本地自动对象t复制到临时对象中以获取函数f()
的返回值 并将该临时对象复制到对象t2
中。实际上,构造了本地对象t
可以看作是直接初始化全局对象t2
,并且该对象的破坏将在程序中发生 出口。向Thing添加移动构造函数具有相同的效果,但它是移动构造 被遗漏的t2
临时对象。 -end example ]