Reputation: 52371
I'm trying to grasp the concept of smart pointers in C++. I have the following piece of code (a unit test using GoogleTest):
TEST(SHT35Sensor, ValidInstruction) {
auto sht35 = SampleSHT35::create();
sht35->add(22.4, 56.5);
char writeBuffer[100] = {0};
auto serial = std::make_unique<SampleSerial>("", writeBuffer, 0);
auto sensor = std::make_unique<SHT35Sensor>(0x03, serial.get(), sht35, 0);
auto actual = sensor->execute(Instruction(0, 0, Bytes("\x02", 1)));
ASSERT_TRUE(actual);
}
I want to isolate the first five lines of the test in order for them to be reused. I thought that it would be enough (and especially it would be correct) to do this:
std::shared_ptr<SHT35Sensor> prepare() {
auto sht35 = SampleSHT35::create();
sht35->add(22.4, 56.5);
char writeBuffer[100] = {0};
auto serial = std::make_unique<SampleSerial>("", writeBuffer, 0);
return std::make_shared<SHT35Sensor>(0x03, serial.get(), sht35, 0);
}
TEST(SHT35Sensor, ValidInstruction) {
auto sensor = prepare();
auto actual = sensor->execute(Instruction(0, 0, Bytes("\x02", 1)));
ASSERT_TRUE(actual);
}
Essentially, I moved the code in a function, and instead of unique_ptr
, I used shared_ptr
in order to be able to share it between the function which creates it and the caller.
However, the second variant leads to a segmentation fault when running the test, meaning that my understanding of smart pointers is incorrect.
What am I doing wrong?
Upvotes: 0
Views: 126
Reputation: 50036
In your code serial.get()
returns pointer, but does not detaches it from unique_ptr
, so when prepare ends
- unique_ptr deletes SampleSerial
instance and shared_ptr
contains pointer to freed memory. You may use serial.release()
or directly use shared_ptr
.
Above answer assumes that SHT35Sensor
will handle lifetime of SampleSerial
instance. But if that is not true then pass unique_ptr<SampleErial>
to SHT35Sensor
:
return std::make_shared<SHT35Sensor>(0x03, std::move(serial), sht35, 0);
Your SHT35Sensor
should accept std::unique_ptr<SampleErial>
as second parameter - and pass it to class member using constructor initialization or once again std::move
.
I would prefer the second solution as no bare pointer will be accepted by SHT35Sensor
- which is good.
Upvotes: 3