如何在不创建副本的情况下 return 对象?

how to return object without create copy of that?

我开发了简单的 c++ class 来测试 c++ 对象何时销毁;现在我有一个问题,当对象 return 通过函数时,c++ 创建一个新对象并 return 并且当 return 引用销毁对象时我的错误是什么?

下面附上简单的class。

#include <iostream>

using namespace std;

static int freeCounter=0;

class TestCopy {
private:
    string pStr;
public:
    TestCopy(const TestCopy &obj){
        pStr=obj.pStr;
    }
    TestCopy(string &test){
        pStr=test;
    }
    ~TestCopy(){ freeCounter++; cout << freeCounter <<"\t" << pStr << endl; }

    TestCopy get(){
        TestCopy x=*this; 
        return TestCopy(x); // -> TestCopy(x) is first destroy in result
    }

    string getStr(){
        return pStr;
    }
};

int main(){
    string xstr="test";
    TestCopy x(xstr); // x is third destroy
    TestCopy x2=x.get(); // x2 is second destroy

    cout << x.getStr() << endl;

    return 0;
}

和结果

1   test
test
2   test
3   test

get函数中的x是局部对象,当函数结束时,x会被销毁。

所以,x是第一个销毁的。

谢谢@seaman 的帮助,我发现了我的错误。 通过更改

TestCopy x=*this;

const TestCopy &x=*this;

问题已解决

首先回顾一下 OP 的代码。我稍微修改了它,使发生的事情更加明显。

#include <iostream>

using namespace std;

static int allocCounter = 0;

class TestCopy
{
private:
    string pStr;
    int counter;
public:
    TestCopy(const TestCopy &obj)
    {
        allocCounter++;
        counter = allocCounter;
        cout << "copy construct " << counter << endl;
        pStr = obj.pStr;
    }
    TestCopy(const string &test)
    {
        allocCounter++;
        counter = allocCounter;
        cout << "string construct " << counter << endl;
        pStr = test;
    }
    ~TestCopy()
    {
        cout << counter << "\t" << pStr << endl;
    }

    TestCopy get()
    {
        TestCopy x = *this; // copy constructed
        return TestCopy(x); // copy constructed and copy elision
    }

    string getStr()
    {
        return pStr;
    }
    TestCopy & operator=(const TestCopy &obj)
    {
        cout << "assigned " << obj.counter << " to "<< counter << endl;

        pStr = obj.pStr;
//        counter = obj.counter; deliberately left out
        return *this;
    }

};

int main()
{
    string xstr = "test";
    TestCopy x(xstr); // string constructed
    TestCopy x2 = x.get(); // Would be a copy constructed if not for copy elision
    return 0;
}

输出

string construct 1
copy construct 2
copy construct 3
2   test
3   test
1   test

请注意,即使使用 TestCopy x=*this;

也不会调用赋值运算符

好的。现在我们如何砍掉其中的一些?

首先我们去掉get

中的冗余副本
TestCopy get()
{
    return *this; // copy constructed. Or is it? The copy construction could
                  // happen at the caller. Either way it is copied and elided
}

输出

string construct 1
copy construct 2
2   test
1   test

所以此时我们知道不需要在 get 中进行复制或赋值,因为 return 语句会为我们完成。这是关于 OP 问题的重要部分。

但是如果我们稍微改变 main 并添加一个赋值运算符,我们可以观察到更有趣的行为。

int main()
{
    string xstr = "test";
    TestCopy x(xstr); // string constructed
    TestCopy x2(""); //string constructed
    x2 = x.get(); // assigned and a copy construct when returning from get
    cout << "done main" << endl;
    return 0;
}

输出

string construct 1
string construct 2
copy construct 3
assigned 3 to 2
3   test
done main
2   test
1   test

get 的 return 被分配给 x2,然后销毁。 x2 被摧毁,最后 x.