如果我写
T t = T();
T是一个班级。
我认为这是调用T的默认构造函数,然后是复制赋值运算符。 但是允许编译器摆脱赋值。
我试图找到用C ++标准编写的这种行为的描述,但我找不到它。 你能指出我在标准中的正确位置吗?
我问这个是因为我被要求更换它:
T t;
与
T t = T();
因为编码规则检查程序。
并且碰巧T类是不可复制的并且具有私有拷贝构造函数和拷贝赋值运算符...... 所以我想看看编译器在这种情况下实际上总是摆脱副本。
修改 我被一些奇怪的东西误导了: 不可编译的类实际上是从boost :: noncopyable继承的 在这种情况下,它确实编译。 但是如果我将复制构造函数和复制赋值运算符声明为private,则它不会编译。 为例。这编译:
class BA
{
protected:
BA() {}
~BA() {}
private:
BA( const BA& );
const BA& operator=( const BA& );
};
class A : BA
{
};
int main( void )
{
A a = A();
return 0;
}
以下不是:
class A
{
public:
A() {}
~A() {}
private:
A( const A& );
const A& operator=( const A& );
};
int main( void )
{
A a = A();
return 0;
}
答案 0 :(得分:7)
构建一个临时文件然后将构建它复制到t
,而不是复制分配它(8.5 / 14)。
复制文件可以省略,但无论如何都必须可以访问(12.8 / 14-15)
答案 1 :(得分:1)
这称为Return Value Optimization。本文还在脚注中提到了相关的C ++标准段落。
如果你想更精确地控制行为,你可以更明确地处理对象,例如通过alloca自己在堆栈上分配临时对象,然后调用placement new运算符。
答案 2 :(得分:1)
在C ++ 0x中,您可以将T t;
替换为T t{};
。
答案 3 :(得分:1)
由于你要求C ++标准引用,这里是:
12.8复制类对象
15
* 当满足某些条件时,允许实现省略类对象的复制结构,即使该对象的复制构造函数和/或析构函数具有副作用。在这种情况下,实现将省略的复制操作的源和目标简单地视为引用同一对象的两种不同方式,并且在两个对象的后期发生对该对象的破坏。 如果没有优化,就会被销毁.111)在下列情况下允许复制操作的省略(可以合并以消除多个副本):
- 在具有类返回类型的函数的return语句中,当表达式是具有与函数返回类型相同的cv-unqualified类型的非易失性自动对象的名称时,复制操作可以通过将自动对象直接构造到函数的返回值中来省略。
- 当一个未绑定到引用(12.2)的临时类对象被复制到具有相同cv-nonqualified类型的类对象时,可以通过直接构造临时对象来省略复制操作进入省略副本的目标 *
示例:
class Thing
{
public:
Thing();
˜Thing();
Thing(const Thing&);
};
Thing f()
{
Thing t;
return t;
}
Thing t2 = f();
这里可以结合使用elision的标准来消除对类Thing的复制构造函数的两次调用:
将本地自动对象t复制到临时对象中以获取函数f()的返回值以及将该临时对象复制到对象t2中。实际上,可以将本地对象t的构造视为直接初始化全局对象t2,并且该对象的破坏将在程序退出时发生。