【问题标题】:Segmentation fault with unique_ptrunique_ptr 的分段错误
【发布时间】:2019-11-21 08:04:52
【问题描述】:

我正在尝试使用 unique_ptr 而不是自己分配内存。 我有以下代码:

class Album {
...
public:
    Add(Song* song);
...
}

void func(){
    ...
    std::unique_ptr<Album> album = std::unique_ptr<Album>{new Album()};
    std::unique_ptr<Song> song = std::unique_ptr<Song>{new Song(soundtrack.data(), soundtrack.length())};
    album->Add(song.get());
    ...
}

我的线路出现分段错误:

album->Add(song.get());

我尝试了多种变体来获取指针,包括 std::move 和 make_unique,但也许我不明白 unique_ptr 是如何工作得足以解决它的。

有什么想法吗?

【问题讨论】:

  • 这还能编译吗?成员函数需要返回类型。
  • Add 应该采用 std::unique_ptr&lt;Song&gt; 而不是 Song*。然后你必须std::movealbum-&gt;Add(std::move(song));
  • @andreee,绝对!但是这里的逻辑表明是Album负责歌曲,而不是func
  • @O.B.我认为您需要提供更多信息。由于滥用unique_ptr(如Evg所述),很可能您的albumsong 实例寿命更长。旁注:You should prefermake_unique 在 ctor 中调用 new
  • 智能“指针”的重点不是管理内存而是管理所有权;它们与实际指针几乎完全不同。它们不是可以让您免于思考生命和所有者的神奇精灵尘埃。使用通过get 获得的原始指针会遇到许多与使用通过&amp; 获得的相同的问题。

标签: c++ segmentation-fault unique-ptr


【解决方案1】:

问题如下

class Album {
...
public:
    Add(Song* song);
...
}

void func(){
    ...
    std::unique_ptr<Album> album = std::unique_ptr<Album>{new Album()};
    std::unique_ptr<Song> song = std::unique_ptr<Song>{new Song(soundtrack.data(), soundtrack.length())};
    album->Add(song.get());
    ...
    // Here the object song gets destructed. This means that the underlying Song gets destructed.
    // So right after leaving func() the pointer that was returned by song.get() now points to non-allocated memory containing random bits at worst case.
}

所以一种可能的解决方案是......

class Album {
...
public:
    Add(std::unique_ptr<Song>&& song); // you still need to move song inside Add(...)
...
}

void func(){
    ...
    std::unique_ptr<Album> album = std::unique_ptr<Album>{new Album()};
    std::unique_ptr<Song> song = std::unique_ptr<Song>{new Song(soundtrack.data(), soundtrack.length())};
    album->Add(std::move(song)); //here song is intended  to be moved inside Add(...)
    ...
    // If moved inside Add(...) song points to nullptr here.
}

【讨论】:

  • 您可以展示您的 Add() 版本,以便详细说明如何调整它。
  • 您不应该将唯一指针作为右值传递,而是按值传递它们
  • 或者作为非常量引用,如果你想接收值。
  • @andreee 如果不将唯一指针作为右值引用传递,因为有点尴尬,我们需要将原始指针与 unique_ptr 对象解除绑定,以防Add(...) 存储指针以供以后使用 - 我想是这种情况并导致段错误。最好不要在 func() 中创建 unique_ptr。但在我看来,这取决于Add() 中做了什么。
  • 此外,您不能将 unique_ptr 作为值传递,因为此类没有 copy-ctor。您可以将底层原始指针作为值传递,也可以使用 (constnon-const) 左值引用,即 std::unique_ptr&lt;...&gt;&amp;。但对我来说,这看起来也不那么尴尬。
【解决方案2】:

您提供的代码编译并运行良好-因此您未提供的部分肯定存在问题-我怀疑Add() 内的代码或其返回类型,或者稍后使用necktschnagge 怀疑的指针。工作示例在 gdbonline:
https://onlinegdb.com/r1oyXGK2S

首先我要问一个问题,您希望通过使用std::unique_ptr 获得什么优势。考虑到一个唯一的指针并不能保证有一个指针——在Add() 内你必须检查nullptr! 我认为从您的用法来看,您不想使用std::unique_ptr

关键是,std::unique_ptr 拥有唯一的所有权。其中之一:

  • func()::本地范围
  • album::Add()::parameter_scope

拥有它。

由于您没有使用std::move(),所有权仍保留在func() 中,并将在func() 结束时销毁。为避免这种情况,您不妨使用song.release()(请参阅 cpp-reference)。

【讨论】:

    猜你喜欢
    • 2013-09-16
    • 2019-10-20
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-20
    • 1970-01-01
    • 2012-04-03
    相关资源
    最近更新 更多