未调用模板类复制构造函数

时间:2015-01-15 12:41:49

标签: c++ templates copy-constructor copy-elision

我的副本构造函数没有被调用,我不知道为什么。这是我的代码:

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>)’"

我在这里做错了什么?

1 个答案:

答案 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 ]