【问题标题】:When are objects destroyed?对象什么时候被销毁?
【发布时间】:2012-11-02 12:49:23
【问题描述】:

我想确认在以下情况下会发生的行为。假设我有一些函数定义为:

std::vector<Object*> FuncA()
Result FuncB()

其中 result 是一个带有构造函数的类

Result(const std::vector<Object*>& result)
{
    this->result = result;
}

现在,FuncB 执行以下操作:

Result FuncB() {
 ... some stuff here ...
return Result(FuncA())
}

FuncA 返回的向量何时会被销毁(调用其析构函数)?当结果超出范围时会是这样吗?持有对它的引用的结果是否会延长其生命周期?如果不能,您能否解释一下原因以及实现我所追求的方法?

谢谢

编辑:这是结果类

class Result
    {
    private:
        std::vector<Object*> result;

        void SetData(const Result& other);
        void Free();

        // Constructs the result and takes ownership of the memory.
        Result(const std::vector<Object*>& result);

        Result();

    public:
        Result(const Result& other);
        Result& operator=(const Result& rhs);
        ~Result();

        const Object& operator [] (int index);
    };

【问题讨论】:

  • 请贴出Result的定义。答案取决于里面存储的内容。
  • 不要使用指针向量,这很容易造成内存泄漏。如果你不想要std::vector&lt;Object&gt;,至少使用std::vector&lt;std::shared_ptr&lt;Object&gt;&gt;

标签: c++ oop class object


【解决方案1】:

如果Result 持有引用,那么您就有问题了。 FuncA返回的对象会在Result对象返回之前销毁。

现在,Result 按价值保留。这意味着FuncA 的返回值将被复制到构造函数中。当Result 对象被销毁时,向量将被销毁。

如果你想避免复制,take the object by value in the constructor

Result(std::vector<Object*> result) 
    : result(std::move(result))
{}

或者,如果您不使用 C++11(参见 @Steve Jessop 的评论)

Result(std::vector<Object*> result) 
{
    this->result.swap (result);
}

【讨论】:

  • 哎呀,这是类定义中的错字,我的意思是在构造函数中有一个引用,但不管你是否回答了我的问题,谢谢。我希望避免先构建向量然后将其复制到 Result,我希望我可以让 Result 有效地拥有它并延长它的生命周期 - 无需复制它。
  • @user1520427:你没有显示构造函数的定义,只有声明,所以我们无法判断它是否被复制,我们必须相信你的话它。但是,由于Result 的构造函数采用非常量引用,因此根据标准,Result(FuncA()) 的格式不正确。 MSVC 允许它作为扩展。此外,该构造函数是私有的,FuncB 不是朋友,所以它的格式不正确还有第二个原因。除非我误解了,否则这不是真正的代码,因此您可能无法得到真正的答案。
  • @AlexandreC.: 从命名构造函数参数(即不是临时)复制到初始化列表中的数据成员时是否允许复制省略?也许我遗漏了一些东西,但我不认为它是,所以我认为Result(std::vector&lt;Object*&gt; result) : result(result) {} 必须复制向量。在 C++11 中,显而易见的事情是有一个右值引用构造函数来移动构造数据成员。
  • @SteveJessop 代码基于真实代码,但我删减了一些内容,只关注问题所在。无论如何,即使我通过引用传递值,它也会在函数内被复制,所以至少会有一份副本?如果我按值传递,可能有两个(一个复制到构造函数,然后一个复制到成员变量)?我对何时使用引用以及何时不使用(以及何时复制内容)感到有些困惑,目前我通常总是使用引用,除非它需要在函数中进行修改。
  • @SteveJessop:在这里你使用std::moveResult(std::vector&lt;Object*&gt; result) : result(std::move(result)) {} 在任何情况下都会正确执行。复制省略发生在构造函数调用站点。
【解决方案2】:

这很可能是做你想做的事情的错误方法。当Result 超出范围时,该向量将被销毁。向量中的指针指向的内存没有。

所以你可以返回一个向量并仍然使用它,但如果该向量副本中的指针被释放,你将遇到 UB。

使用std::vector&lt;std::shared_ptr&lt;Object&gt;&gt; 可以为您省去很多麻烦。

【讨论】:

  • 使用这个类的原因之一是为了处理内存问题,当它被销毁时它会释放所有指针。但是,是的,我可能应该使用 shared_ptrs :/
  • @user1520427 完全正确。但是当指针被销​​毁时释放指针可能会给你留下那些现在无效的指针的副本。
  • 嗯,这是真的,尽管我打算如何在这种特定情况下使用它,但我认为我不会遇到这个问题。但无论如何,在大多数情况下应该使用共享的ptrs吗?什么情况下最好不要使用它们?
  • @user1520427 不应该使用shared_ptr 的情况是可以使用unique_ptr。在您的情况下,似乎所有权是共享的,这就是为什么我没有首先建议unique_ptr。但除此之外,您应该始终更喜欢它们而不是原始的 C 样式指针。
猜你喜欢
  • 2023-03-31
  • 2019-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
相关资源
最近更新 更多