Ошибка сегментации с unique_ptr - PullRequest
0 голосов
/ 21 ноября 2019

Я пытаюсь использовать 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 работает достаточно хорошо, чтобы решить ее.

Есть идеи?

Ответы [ 2 ]

1 голос
/ 25 ноября 2019

Код, который вы предоставили, компилируется и работает нормально - поэтому в той части, которую вы не предоставили, должна быть проблема - я подозреваю, что код внутри Add() или его возвращаемый тип, или некоторое позднее использование указателей как necktschnagge Подозреваемый. Рабочий пример на gdbonline:https://onlinegdb.com/r1oyXGK2S

Прежде всего, я задаю вопрос, Какое преимущество вы хотели бы получить , используя std::unique_ptr. Учтите, что уникальный указатель не гарантирует наличие pointee - внутри Add() вы должны проверить на nullptr! Я думаю, что из вашего использования вы не хотите использовать std::unique_ptr:

Ключ в том, что std::unique_ptr имеет только уникальное право собственности. любой из них:

  • func() :: локальная область действия
  • album::Add() :: parameter_scope

владеет им.

Поскольку вы не использовали std::move(), владение остается в func() и будет уничтожено к концу func(). Чтобы избежать этого, вы также можете использовать song.release() (см. cpp-reference ).

1 голос
/ 21 ноября 2019

Проблема заключается в следующем

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.
}
...