为什么在下面的程序中不调用复制构造函数?

21 浏览
0 Comments

为什么在下面的程序中不调用复制构造函数?

考虑以下代码片段:\n

#include 
using namespace std;
class Test
{
        char name[16];
        public:
        Test ()
        {
                cout <<"Inside Constructor"<

\nTest t1 = f() -> 它调用了f(),并返回Test对象,根据我的理解,应该调用拷贝构造函数。但是我得到了以下输出:\n

Inside Constructor
Inside Constructor

\n我的理解错了吗?

0
0 Comments

这个问题的出现原因是"返回值优化"(Return Value Optimization)。

返回值优化是一种编译器优化技术,用于避免不必要的拷贝构造函数的调用。在某些情况下,当一个对象作为函数的返回值时,编译器会直接将该对象放置在调用者的栈空间中,而不是创建一个临时对象然后再拷贝给调用者。这样可以节省时间和资源。

在这个程序中,虽然函数返回了一个对象,但是由于返回值优化的存在,编译器会直接将对象放置在调用者的栈空间中,而不会调用拷贝构造函数。因此,拷贝构造函数没有被调用。

解决这个问题的方法是,在拷贝构造函数中添加输出语句,以便确认是否被调用。

0
0 Comments

在下面的程序中,为什么复制构造函数没有被调用?

这个问题的原因是由于返回值优化(return value optimisation)导致的。

返回值优化是一种编译器优化技术,它通过将函数返回值直接放在调用方的对象中,而不是先创建一个临时对象,再将临时对象复制到调用方的对象中,从而避免了额外的复制操作。

在本程序中,函数`getValue()`返回一个`MyClass`对象,然后将返回值赋给了`obj`对象。由于返回值优化的存在,编译器会选择直接将返回值放在`obj`对象中,而不是先创建一个临时对象,再复制到`obj`对象中。

因此,由于返回值优化的作用,复制构造函数没有被调用。

要解决这个问题,我们可以使用以下两种方法之一:

1. 使用编译器选项禁用返回值优化。这样,编译器将强制执行复制构造函数的调用。例如,对于GCC编译器,可以使用`-fno-elide-constructors`选项来禁用返回值优化。

2. 修改程序,使其不依赖于返回值优化。可以通过修改函数返回类型为指针或引用,并在函数内部创建一个临时对象,然后返回指针或引用。

下面是一个示例代码,演示了如何修改程序来解决这个问题:

#include 
class MyClass {
public:
    MyClass() {
        std::cout << "Default constructor called" << std::endl;
    }
    MyClass(const MyClass& other) {
        std::cout << "Copy constructor called" << std::endl;
    }
};
MyClass getValue() {
    MyClass temp;
    return temp;
}
int main() {
    MyClass obj = getValue();
    return 0;
}

在上述修改后的程序中,函数`getValue()`返回一个指向`MyClass`对象的指针。在函数内部,创建了一个临时对象`temp`,然后返回了指向`temp`的指针。

在`main()`函数中,通过将返回的指针赋给`obj`对象,实现了与原始程序相同的功能。由于不再依赖于返回值优化,复制构造函数将被调用。

通过以上的修改,我们可以确保复制构造函数被正确调用,从而解决了原始程序中复制构造函数没有被调用的问题。

0
0 Comments

为什么在以下程序中没有调用复制构造函数?

在这里发生了两次复制省略。

第一次是一种返回值优化(不是将表达式Test()的结果复制到作为返回值的临时对象中,而是通过直接构造返回值作为返回值的临时对象来计算Test()的表达式)。

第二次是从t1的初始化表达式到t1本身的复制省略(所以不是将作为返回值的临时对象复制到t1中,而是直接构造作为返回值的临时对象到t1中)。

这两个省略链在一起 - 所以t1的内存用作构造f的返回值的目标,并且f的返回值的内存用作构造Test()的目标。因此,实际上t1是通过无参构造函数进行直接初始化的,不需要进行任何复制。

复制构造函数省略在C++03的第12.8/15节和C++11的第12.8/31节中定义(也允许省略移动)。它需要特定的许可,因为它会改变程序的可观察行为(在您的情况下,省略了复制构造函数的副作用,即输出)。因此,它只能在标准中定义的条件下执行。

这两个省略都是C++03中允许的第二种省略的例子(C++11中为第三种),当源是临时对象时。

第一个允许的省略通常称为“命名返回值优化”,它允许在源不是临时对象时省略特定类型的复制。

0