Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在这种情况下不调用复制构造函数?_C++_Constructor_Copy Constructor - Fatal编程技术网

C++ 为什么在这种情况下不调用复制构造函数?

C++ 为什么在这种情况下不调用复制构造函数?,c++,constructor,copy-constructor,C++,Constructor,Copy Constructor,以下是小代码片段: class A { public: A(int value) : value_(value) { cout <<"Regular constructor" <<endl; } A(const A& other) : value_(other.value_) { cout <<"Copy constructor" <<endl; }

以下是小代码片段:

class A
{
public:
    A(int value) : value_(value)
    {
        cout <<"Regular constructor" <<endl;
    }

    A(const A& other)   : value_(other.value_)  
    {
        cout <<"Copy constructor" <<endl;
    }

private:
    int value_;
};
int main()
{
    A a = A(5);
}
A类
{
公众:
A(int值):值(value)
{
cout来自另一条评论:“因此默认情况下我不应该依赖它(因为它可能依赖于编译器)”

不,实际上它并不依赖于编译器。任何一个有价值的编译器都不会浪费时间构造一个a,然后复制它

在该标准中,它明确指出,
T=x;
等同于说
T(x);
(§12.8.15,第211页)用
T(T(x))
这样做显然是多余的,因此它删除了内部
T

要获得所需的行为,您需要强制编译器默认构造第一个:

A a;
// A is now a fully constructed object,
// so it can't call constructors again:
a = A(5);

这里,您可以从临时代码< >(5)< /C>中初始化<代码> A<代码>代码。允许执行跳过调用复制构造函数的C++标准12.2/2。

A a = A(5);
这条线相当于

A a(5);

尽管其函数样式外观,第一行仅用参数5构造<代码> A/COD>。没有复制或临时性。从C++标准,第121.11:

函数表示法类型转换(5.2.3)可用于创建其类型的新对象 语法看起来像是构造函数的显式调用。-结束说明]


我在研究这个问题是为了回答另一个被当作傻瓜的问题,所以为了不让工作白白浪费,我现在回答这个问题

形式为
A A=A(5)
的语句称为变量
A
的复制初始化。C++11标准8.5/16规定:

使用初始值设定项表达式调用所选函数,如下所示 它的参数;如果函数是构造函数,则调用初始化 目标类型的cv非限定版本的临时版本 temporary是一个prvalue。调用的结果(即临时 对于构造函数的情况),则根据 根据上述规则,对象是 复制初始化。在某些情况下,允许实现 要消除此直接初始化中固有的复制,请执行以下操作: 将中间结果直接构造到正在生成的对象中 已初始化;请参见12.2、12.8

这意味着编译器会查找适当的构造函数来处理
A(5)
,创建一个临时文件并将该临时文件复制到
A
中。但是在什么情况下可以消除复制

让我们看看12.8/31是怎么说的:

当满足某些条件时,允许忽略实现 类对象的复制/移动构造,即使复制/移动 对象的构造函数和/或析构函数有副作用。In 在这种情况下,实现将处理 省略了复制/移动操作,仅作为两种不同的引用方式 对于同一对象,该对象的销毁发生在 后来这两个物体会被摧毁 没有优化。这省略了复制/移动操作, 在下列情况下,允许复制省略 (可组合使用以消除多个副本):

[……]

  • 复制/移动未绑定到引用(12.2)的临时类对象时 对于具有相同cv类型的类对象,可以执行复制/移动操作 通过将临时对象直接构造到省略的复制/移动的目标中来省略
记住所有这些,下面是表达式
aa=A(5)
的用法:

  • 编译器会看到带有副本初始化的声明
  • 选择
    A(int)
    构造函数初始化临时对象
  • 由于临时对象未绑定到引用,并且它与复制初始化表达式中的目标类型具有相同的类型
    a
    ,因此允许编译器直接将对象构造到
    a
    ,从而省略临时对象

  • 谢谢GMan,我无论如何都不使用这个语法。只是要记住一些东西。哦,刚刚在MSDN上找到:C++标准允许复制构造函数的删除(参见第12.8节。复制类对象,第15段)。谢谢,我现在看到了。在答案中引用有点多,所以我将按数字引用。这取决于编译器。标准允许不同的行为,请参见我的答案。它是优化的,避免了构造+复制。我发现这是一个很好的假设,没有用户会根据参数构造,这与复制构造的方式不同。请参见:在g++中,您可以使用选项-fno elide constructors禁用此优化。我认为这不正确。12.2.2中的示例涉及在构造本地对象之前将临时对象传递给函数。不,它不是等效的。一个是复制初始化,另一个是直接初始化。