-1

I am currently trying to wrap my head around on how to properly use C++ smart pointers. I keep reading that I should use make_unique() most of the time, but I always get segfaults with them and I am unsure on how to properly use them.

I am trying to instantiate some Protocol Buffers generated classes for testing purpose. Here's what I am trying to do:

using namespace std;
#include <catch.hpp>

class Fixtures {
public:
    std::unique_ptr<DescendingMessage> getDescendingMessage();

    std::unique_ptr<VehicleCommand> getVehicleCommand_Door();

    std::unique_ptr<Door> getDoorCommand_open();



};

unique_ptr<DescendingMessage> Fixtures::getDescendingMessage() {
    auto descendingMessage = make_unique<DescendingMessage>();
    descendingMessage->set_allocated_vehicle_command(getVehicleCommand_Door().get());
    return move(descendingMessage);
}

unique_ptr<VehicleCommand> Fixtures::getVehicleCommand_Door() {
    auto vehicleCommand = make_unique<VehicleCommand>();
    vehicleCommand->set_allocated_door_operation(getDoorCommand_open().get());
    return move(vehicleCommand);
}

unique_ptr<Door> Fixtures::getDoorCommand_open() {
    auto door = make_unique<Door>();
    door->set_mode(Door_Mode_OPEN);
    return move(door);

}


SCENARIO("Get a sample protobuf model from Fixtures and test its content") {
    auto fixtures = make_unique<Fixtures>();
    auto descendingMessage = fixtures->getDescendingMessage();

    REQUIRE(!descendingMessage->has_metadata());
    REQUIRE(!descendingMessage->has_state_request());
    REQUIRE(descendingMessage->has_vehicle_command());

}

Whenever I instantiate my Fixtures class in my Catch2 Test, I get a segmentation fault when I try to get an instance of DescendingMessage. I know it has to do with memory getting freed twice, but I don't know how to properly fix this issue. I tried with shared_ptr and it does the same thing. What am I missing here? I would really like to use smart pointers but I am getting nowhere with them for now :/

  • 1
    The provided code doesn't compile - please provide a real [mcve] – UnholySheep Apr 05 '18 at 18:48
  • Updated code above with my real code instead of pseudo-code – Frederic Portaria-Janicki Apr 05 '18 at 18:56
  • 1
    That still does not fulfill the criteria of an [mcve] - we cannot compile this code and see for ourselves. Though `getVehicleCommand_Door().get()` indicates to me that you are passing raw pointers here, which point to objects that get destroyed right afterwards – UnholySheep Apr 05 '18 at 19:02
  • Oh I see, sorry I am not used to ask questions here :/ The base models are protocol buffers models, which would be pretty big to post here. I'll find the method signature – Frederic Portaria-Janicki Apr 05 '18 at 19:06
  • And yes you are right, they accept raw pointers – Frederic Portaria-Janicki Apr 05 '18 at 19:06
  • 1
    In that case (based on the names of the functions) you are storing dangling pointers in your classes - why not make the functions themselves accept `unique_ptr`s (and store said `unique_ptr`s as class members)? – UnholySheep Apr 05 '18 at 19:08
  • The DescendingMessage, Door and VehicleCommand are generated by a compiler called ProtocolBuffers, I don't have control on their implementation. I just know that they accept a raw pointer. Somehow, it seems like the `unique_ptr` deleter gets called even after I return it through the move semantics. – Frederic Portaria-Janicki Apr 05 '18 at 19:17
  • Alright I found the solution in this thread: https://stackoverflow.com/questions/43514048/how-do-i-pass-protobufs-boostshared-ptr-pointer-to-function I basically replaced the get() (thanks to you) to a release() and it seems to be working now! – Frederic Portaria-Janicki Apr 05 '18 at 19:22

1 Answers1

2

You need to pass ownership of your smart pointers.

You are currently using unique_ptr::get() which only returns the raw pointer.

When passing ownership use unique_ptr::release() which returns the pointer and releases ownership.

In your code:

// object used to set vehicle command 
//    but object is still owned by unique_ptr
set_allocated_vehicle_command(getVehicleCommand_Door().get());

// object is used to set vehicle command
//    and ownership is released from unique_ptr
set_allocated_vehicle_command(getVehicleCommand_Door().release());