guyutongxue/MyCppTutorial

关于复制构造函数的疑问

Closed this issue · 2 comments

你好。我在看你的“谷雨同学的C++教程”时,在看到第五章的复制构造函数部分时,遇到一个复制构造函数调用的问题,下面是的代码:

#include <iostream>
#include <cstring>

struct String {
   char* str;
   unsigned len;
   String(unsigned num, char c){
        len = num;
        str = new char[num + 1];
        unsigned i{0};
        for(i;i < num;i++)
           str[i] = c;
        str[i + 1] = '\0';
   }

   String(const char* strVa){
       len = std::strlen(strVa);
       unsigned i{0};
       str = new char[len + 1];
       for(i;i < len;i++)
           str[i] = strVa[i];
       str[i + 1] = '\0';
   }

   String(){
       len = 0;
       str = new char[1]{'\0'};
   }

   String(const String& s){
       std::cout << "Copy func structor" << std::endl;
   }
};

class S{
   public:
       S(){
           std::cout << "func structor" << std::endl;
       }

       S(const S& s){
           std::cout << "Copy func structor" <<std::endl;
       }
};

void f(String d){
   std::cout << "f" << std::endl;
}

void f(S s){}

String g(void){
   String sth("hello");
   return sth;
}

S h(void){
   S e;
   return e;
}

int main(){
   String a;
   String b(3,'o');
   String c("Hello");
   S e;
   a = g();  //此处调用了复制构造函数
   f(c);      //struct中声明的复制构造函数,在此处f没有调用复制构造函数,
   std::cout << "endl" << std::endl;
   e = h(); //此处没有调用复制构造函数
   f(e);      //class中声明的复制构造函数,在此处f调用了额复制构造函数。
}

我分别创建了String结构体和S类,我按照教程创建了两个函数来实现复制构造,然而我发现T g(void){}函数在返回的对象是结构体创建时会调用复制构造函数,若返回的对象时类创建的则不会,同样,void f(T t){}函数在调用时传入的对象是结构体创建的则不会调用复制构造函数,反之,若是类创建的则会调用构造函数。此处是否教程有问题?
注:编译器使用的是GCC,C++14。

你刚刚好看错了。

a = g(); 没有调用复制构造函数,因为有复制消除(NRVO)。你观察到的“调用复制构造函数”,恰恰是下一行的 f(c);

e = h(); 同理,因为 NRVO 没有调用复制构造函数。你观察到的调用,确实是下一行的 f(e);

你可以删除两条赋值,你仍然会观察到同样的输出结果,这证明了调用复制构造与否,与如何声明类是无关的。

你刚刚好看错了。

a = g(); 没有调用复制构造函数,因为有复制消除(NRVO)。你观察到的“调用复制构造函数”,恰恰是下一行的 f(c);

e = h(); 同理,因为 NRVO 没有调用复制构造函数。你观察到的调用,确实是下一行的 f(e);

你可以删除两条赋值,你仍然会观察到同样的输出结果,这证明了调用复制构造与否,与如何声明类是无关的。

谢谢,我删除两条复制后进行测试,确实如你所说结果一样。现在也理解了,感谢解答!