【问题标题】:What happens with return value?返回值会发生什么?
【发布时间】:2015-07-10 21:01:01
【问题描述】:

所以我在这个例子中有 2 个类:
E,当它被销毁时打印一条消息 + 可以存储整数值
T,它存储E 的实例并可以返回它通过方法

代码:

class E
{
public:
    E();
    ~E();
    int test;
};

E::E(){}
E::~E()
{
    std::cout << "E is destroyed" << std::endl;
}

///////////////////////////////////////////

class T
{
public:
    T();
    ~T();
    E data;
    E get();
};

T::T(){}
T::~T(){}
E T::get()
{
    return this->data;
}

///////////////////////////////////////////

int main()
{
    E e;
    e.test = 2;

    T t;
    t.data = e;

    E* e2;
    {      
        e2 = &(t.get());
        std::cout << "end of block" << std::endl;
    }

    std::cout << e2->test;
}

运行我的代码的结果是:

E is destroyed
end of block

这意味着E 的某些实例在到达{} 的末尾之前被销毁

问题:
1.我做了一点实验。 e2 = &amp;(t.get()); 行中的 t.get() 值是否正确,因为它没有按值分配给任何变量?
2.如果这个值被破坏,那意味着e2指针无效。但是std::cout &lt;&lt; e2-&gt;test; 行仍然打印保存的整数值。指针是否仍然有效,或者这些数据只是偶尔停留在这个内存位置?

【问题讨论】:

  • 是的,你有一个dangling pointer 指向一个超出范围的变量。在此之后尝试对该对象执行任何操作都是未定义的行为。
  • 请注意,如果您的函数具有签名E&amp; T::get(),您将返回对仍在范围内的data 的引用,这样就可以了。问题是您按值返回了 E,这是一个立即被销毁的临时值。
  • @Cyber​​,是的,我就是这么想的,谢谢。我读过一些关于临时工的东西,但不确定这是否完全是关于我的情况。那么,我对此是否正确:如果临时通过值立即分配给某物,它肯定不会被销毁,是吗?

标签: c++ pointers return


【解决方案1】:

默认情况下,释放的内存未设置为特定值。因此,它保留了它拥有的最后一个值。发生的情况是您的 t-> 数据 副本 的地址存储在 e2 中。然后,编译器释放所述副本,因为您不再使用它。因此,您可以调用析构函数。

但是,您确实将值 保存在内存中,因此您的指针仍然可以访问它们。 (但我猜想 valgrind 会吐出无效的读取。)

所以是的,您的指针确实无效,但它仍然可以访问数据。

重新措辞以合乎逻辑地回答您的问题:

1) 它是一个副本,并没有立即分配,因此被立即销毁。

2) 值存在于地址中,但地址被视为无效并可能导致内存问题(例如分段错误)

【讨论】:

    【解决方案2】:

    原始代码不会被 GCC 编译,因为函数

    E T::get()
    {
        return this->data;
    }
    

    返回值。当您在块中分配指针e2 = &amp;(t.get()); 时,它会生成data 的临时副本。从块中退出后,当您引用指针e2 时,它不再指向实际变量,因为临时变量超出了范围。所以为了纠正这个问题,你可以修改代码以返回对T类的data字段的引用:

    E& T::get()
    {
        return data;
    }
    

    之后当你再次运行代码时,你会看到:

    end of block
    2
    E is destroyed
    E is destroyed
    

    注意这两个E is destroyed是因为有两个E实例,一个用于e,另一个用于t.data,因为代码t.data = e;会调用类的复制构造函数E。因此最终有两个E对象在程序退出时被破坏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-02
      • 2012-10-23
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 2019-10-29
      • 2014-11-15
      • 1970-01-01
      相关资源
      最近更新 更多