如何返回对象而不创建该对象的副本

how to return object without create copy of that?

本文关键字:对象 创建 副本 返回 何返回      更新时间:2023-10-16

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

下面附上一个简单的类。

#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是第一个被破坏的。

首先回顾一下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的返回被分配给x2,然后被销毁。CCD_ 6被破坏,最后CCD_。

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

TestCopy x=*this;

带有

const TestCopy &x=*this;

问题已解决