【问题标题】:how to return object without create copy of that?如何在不创建副本的情况下返回对象?
【发布时间】:2015-12-15 06:36:12
【问题描述】:

我开发了简单的 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

【问题讨论】:

  • 问题是这些TestCopy都不是动态分配的,所以当超出范围时它们会被销毁。
  • 你必须明确表示你在函数签名TestCopy&amp; get(){中返回一个引用,注意我添加的'&'
  • 不完全正确,@Rodolfo。复制省略将在返回问题上处理复制构造,并返回一个本地作为引用将在 MohsenTi 的脸上爆炸,因为返回的引用将不再存在。 Moe 复制省略:stackoverflow.com/questions/12953127/…
  • return *this; 将是最简单、最有效的方法。

标签: c++ object reference destroy


【解决方案1】:

函数get中的x是一个本地对象,当函数结束时,x会被销毁。

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

【讨论】:

    【解决方案2】:

    首先回顾一下 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,然后被销毁。 x2 被销毁,最后是 x

    【讨论】:

      【解决方案3】:

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

      TestCopy x=*this;
      

      const TestCopy &x=*this;
      

      问题解决了

      【讨论】:

      • 既然你可以说return *this;,为什么还需要x
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-05-12
      • 1970-01-01
      • 2010-09-19
      • 1970-01-01
      • 2016-11-25
      • 2021-09-16
      • 1970-01-01
      相关资源
      最近更新 更多