Reputation: 39
I am trying to use unique_ptr instead of allocating memory myself. I have the following code:
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());
...
}
I get segmentation fault for the line:
album->Add(song.get());
I tried multiple variations to get the pointer, including std::move and make_unique, but maybe I don't understand how unique_ptr works well enough to solve it.
Any ideas?
Upvotes: 2
Views: 8660
Reputation: 427
The problem is as follows
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.
}
So one possible solution would be...
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(...)
...
// song points to nullptr here.
}
Upvotes: 1
Reputation: 74
The code you provided compiles and runs fine - thus there must be a problem in the part you didnot provide - I suspect code inside Add()
or it's returntype, or some later use of the pointers as necktschnagge suspected. Working example is on gdbonline:
https://onlinegdb.com/r1oyXGK2S
First of all I ask the question, what is the advantage you'll like to achive by use of std::unique_ptr
. Consider that a unique pointer does not guarantee to have a pointee - inside Add()
you have to check for nullptr
!
I think from your usage, you do not want to use a std::unique_ptr
:
Key is, that a std::unique_ptr
has just a unique ownership. either one of those:
func()
::local scope album::Add()
::parameter_scopeownes it.
Since you didn't use std::move()
the ownership remains in func()
, and will be destroyed by the end of func()
. To avoid this you might as well use song.release()
(see cpp-reference).
Upvotes: 1