C++复制构造函数调用

发布于 2024-08-12 07:35:00 字数 1473 浏览 5 评论 0原文

据我所知,在以下情况下会调用复制构造函数:

1) Pass by value
2) Return by value
3) When you create and initialize a new object with an existing object

这是程序:

#include <iostream> 
using namespace std; 
class Example 
{ 
    public:
        Example() 
        {
            cout << "Default constructor called.\n";
        }
        Example(const Example &ob1) 
        {
            cout << "Copy constructor called.\n";
        }
        Example& operator=(const Example &ob1) 
        {
            cout << "Assignment operator called.\n"; 
            return *this;
        }
        ~Example()
        {
            cout<<"\nDtor invoked"<<endl;
        }
        int aa;
};

Example funct() 
{
    Example ob2;
    ob2.aa=100;
    return ob2;
}



int main() 
{
    Example x;
    cout << "Calling funct..\n";
    x = funct();
    return 0;
}

输出是:

调用默认构造函数。

调用函数..

调用默认构造函数。

调用赋值运算符。

Dtor 被调用

Dtor 被调用

请纠正我,IIRC 应该发生以下调用顺序:

1) 调用 x 的构造函数

2) 调用 ob2 的构造函数

3) 函数返回,因此调用复制构造函数(将 ob2 复制到未命名的临时变量)即 funct() )

4) 调用 ob2 的析构函数

5) 将未命名的临时变量分配给 x

6) 销毁临时变量,即调用其析构函数

7) 销毁 x,即调用 x 的析构函数

但是为什么不调用复制构造函数,而且只调用了 2 次to dtors 在那里,而我期望 3。

我知道编译器可以进行优化,但是,我的理解正确吗?

非常感谢:)

问候

拉利

As far as i know, a copy constructor is invoked in the following scenarios :

1) Pass by value
2) Return by value
3) When you create and initialize a new object with an existing object

Here's the program :

#include <iostream> 
using namespace std; 
class Example 
{ 
    public:
        Example() 
        {
            cout << "Default constructor called.\n";
        }
        Example(const Example &ob1) 
        {
            cout << "Copy constructor called.\n";
        }
        Example& operator=(const Example &ob1) 
        {
            cout << "Assignment operator called.\n"; 
            return *this;
        }
        ~Example()
        {
            cout<<"\nDtor invoked"<<endl;
        }
        int aa;
};

Example funct() 
{
    Example ob2;
    ob2.aa=100;
    return ob2;
}



int main() 
{
    Example x;
    cout << "Calling funct..\n";
    x = funct();
    return 0;
}

The output is:

Default constructor called.

Calling funct..

Default constructor called.

Assignment operator called.

Dtor invoked

Dtor invoked

Please correct me, IIRC the following sequence of calls should occur :

1) Constructor of x is called

2) Constructor of ob2 is called

3) The function returns and so copy constructor is invoked (to copy ob2 to unnamed temporary variable i.e funct() )

4) Destructor of ob2 called

5) Assign the unnamed temporary variable to x

6) Destroy temporary variable i.e invoke its destructor

7) Destroy x i.e invoke x's destructor

But then why copy constructor is not invoked and also only 2 calls to dtors are there whereas i expect 3.

I know compiler can do optimizations, however, is my understanding correct ?

Thanks a lot :)

Regards

lali

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

往事风中埋 2024-08-19 07:35:00

当您按值返回时,复制构造函数可能不会被调用。一些编译器使用返回值优化功能。

了解“返回值优化

A copy constructor might not be invoked when you return by value. Some compilers use return value optimization feature.

Read about "Return Value Optimization"

走过海棠暮 2024-08-19 07:35:00

标准中告诉您编译器何时可以删除副本的部分是 12.8/15。是否实际执行省略始终取决于编译器。有两种合法情况,以及它们的任意组合:

  • “在具有类返回类型的函数中的 return 语句中,当表达式是非易失性自动对象的名称,其类型与以下内容相同:函数返回类型"

  • < p>“当尚未绑定到引用的临时类对象将被复制到具有相同 cv-unqualified 类型的类对象时”。

前者通常称为“命名返回值优化”,它允许您在示例中看到的输出。后者实际上将复制初始化转换为直接初始化,例如,如果您的代码执行了 Example x = Example();,则可能会发生这种情况。

不允许其他复制省略,当然,通常的“假设”规则适用除外。因此,如果复制构造函数具有跟踪功能,那么以下代码必须调用它:

Example x;
Example y = x;

但是如果 x 未被使用,并且 cctor 没有副作用,那么我认为它可以被优化掉,只需就像任何其他不执行任何操作的代码一样。

The part of the standard which tells you when compilers may elide copies is 12.8/15. It's always up to the compiler whether to do actually perform the elision. There are two legal situations, plus any combination of them:

  • "in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type"

  • "when a temporary class object that has not been bound to a reference would be copied to a class object with the same cv-unqualified type".

The former is usually referred to as the "named return value optimization", and it's what permits the output you're seeing in your example. The latter in effect turns copy-initialization into direct initialization, and could occur for instance if your code did Example x = Example();.

Other copy elisions are not permitted, except of course that the usual "as-if" rules apply. So if the copy constructor has tracing in, then the following code must call it:

Example x;
Example y = x;

But if x were otherwise unused, and the cctor had no side-effects, then I think it could be optimized away, just like any other code that does nothing.

撞了怀 2024-08-19 07:35:00

当执行 x = funct(); 时编译器注意到它将直接返回,从而避免无用的构造。这也是为什么您只会收到两次析构函数调用。

这就是为什么有时使用“复制”并不一定会导致性能损失的一个例子。

When doing x = funct(); the compiler notices that it will be directly returned and thus avoids a useless construction. That's also why you will only get two destructor calls.

This is a example why sometimes working with "copy" isn't necessarily a lost of performances.

纸短情长 2024-08-19 07:35:00

在您的示例中,结构足够小,因此它通过寄存器传递。生成的代码类似于返回值优化。构造一个更复杂的示例,您将看到预期的行为。

In your exampe the structure is small enough therefore it is passed through a register. The generated code is similar to Return value optimization. Construct a more complicated example, and you'll see the behavior expected.

只想待在家 2024-08-19 07:35:00

g++ v4.4.1 有一个选项可以抑制“elide”优化:

tst@u32-karmic$  g++ -fno-elide-constructors Example.cpp -o Example

tst@u32-karmic$  ./Example 

Default constructor called.
Calling funct..
Default constructor called.

Copy constructor called.

Dtor invoked
Assignment operator called.

Dtor invoked

Dtor invoked

如您所见,现在调用了复制构造函数!

g++ v4.4.1 has an option to suppress "elide" optimizations:

tst@u32-karmic$  g++ -fno-elide-constructors Example.cpp -o Example

tst@u32-karmic$  ./Example 

Default constructor called.
Calling funct..
Default constructor called.

Copy constructor called.

Dtor invoked
Assignment operator called.

Dtor invoked

Dtor invoked

As you can see the copy constructor is now called!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文