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 :/
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());
Related
I have a QList and I'm trying to replace the objects in the list with new objects. The context is that I have a list of custom objects (the class name is "Conversation") to represent a list of group chats in a messaging platform. I use std::find_if to iterate through the list of pointers to find one with the right ID, and I want to take the pointer to that found object, deallocate it (delete?), and reassign that pointer to point at an object I generate with the "new" keyword. I think I'm doing this right but I'm not sure how to verify.
I tried a couple different iterations, ran into some issues where I realized I was using a const_iterator rather than just an iterator, so I couldn't modify any data. But I've fixed that and it seems like it's working, but I'm not positive.
Here's what I've got:
GroupChat *gc = new GroupChat(); // extends Conversation
// ...I update the member data here...
auto foundChat = std::find_if(conversations_.Conversations.begin2(),
conversations_.Conversations.end2(),
[this, gc](Conversation* o) { // my code to find the correct one...
}
if (foundChat != conversations_.Conversations.end()) {
auto c = (*foundChat);
delete c; // Is this right? Not positive...
//*foundChat = nullptr; // do I need this?
c = gc;
}
It seems like it's working but I'm worried about dangling pointers and incorrect memory deallocation/allocation. Could someone spot check me on this? Thanks for any help!
I am writing a game in which one Object has an ability to turn into an object of another class (e.g. Clark Kent -> Superman). I would like to know what is the most efficient way to implement this.
The logic of my current code:
I have created a turnInto() function inside the ClarkKent class. The turnInto function calls the constructor of Superman class, passing all needed infos to it. The next step is to assign the address of Superman object to the current ClarkKent object.
void ClarkKent::turnInto() {
Superman sMan(getName(), getMaxHP(), getDamage());
&(*this) = &w; // <- error here
this->ClarkKent::~ClarkKent();
}
As you might have guessed, the compiler gives an error that the expression is not assignable. Not sure how to find a correct solution to this.
Keep it simple and don't play tricks you don't understand with your objects.
Superman ClartkKent::turnInto() {
return {getName(), getMaxHP(), getDamage()};
}
At the callee:
ClartkKent some_guy{...};
auto some_other_guy = some_guy.tunInto();
Or if you need something fancy:
using NotBatman = std::variant<ClartkKent, Superman>;
NotBatman some_guy = ClartkKent{...};
using std::swap;
swap(some_guy, some_guy.tunInto());
IDK
I am not sure if I can produce a compile-able example because my issue is a call to a third party library so its difficult to see what is happening (unless you have RTI DDS installed). But I will try to make it as complete an example as I can:
I am using RTI DDS library with C++11. Here is a code snippet that would work:
#include <dds/dds.hpp> // the RTI libs
int main()
{
dds::domain::DomainParticipant participant(0); // 0 is domain_id
dds::topic::Topic<MyTopic> topic(participant, "example");
dds::sub::DataReader<MyTopic> *reader = new dds::sub::DataReader<MyTopic>(dds::sub::Subscriber(participant), topic);
// Now pass the dereferenced reader pointer to the status condition c'tor
dds::core::cond::StatusCondition condition(*reader);
return 0;
}
So this is just a snippet that works, but I would like to have my status condition to be a member variable so that it lives within a class scope and I can use it in various places. I also want to use smart pointers for their auto-destruction properties.
But if I use a unique_ptr instead of a raw pointer I get an error - so I assumed this was because unique_ptr has some protection from being copied or such.
So I thought maybe a shared pointer might be useable here:
#include <dds/dds.hpp> // the RTI libs
int main()
{
dds::domain::DomainParticipant participant(0); // 0 is domain_id
dds::topic::Topic<MyTopic> topic(participant, "example");
std::shared_ptr<dds::sub::DataReader<MyTopic>> shared_ptr_reader = std::shared_ptr<dds::sub::DataReader<MyTopic>>(new dds::sub::DataReader<MyTopic>(dds::sub::Subscriber(participant), topic));
// Now pass the dereferenced reader pointer to the status condition c'tor
dds::core::cond::StatusCondition condition(*shared_ptr_reader); // <-- Crashes here
return 0;
}
This crashes - throws a low-level RTI exceptpion, the stack trace is really not helping me since its deep in the guts of the RTI library :(
The API for the constructor of StatusCondition is here:
dds::core::cond::StatusCondition::StatusCondition ( const dds::core::Entity & entity )
inline
Obtains a reference to the StatusCondition in an entity. Parameters.
entity The Entity whose status condition we're getting a reference to.
There is exactly one StatusCondition per Entity and one Entity per
StatusCondition. NoteThis constructor doesn't create a new Condition.
It obtains a reference to the StatusCondition that each Entity owns.
You can use this constructors as many times as needed to obtain a
reference to the same StatusCondition.
So it looks like it is referencing some internal of the DataReader that is pointed to by the shared_ptr.
So my question is, is there any reason that a shared_ptr would not work in this case compared to a raw pointer?
I'm currently developing application using gSoap library and has some misunderstanding of proper usage library. I has generated proxy object (-j flag) which wrapped my own classes, as you can see below. Application must work 24/7 and connect simultaneously to many cameras (~50 cameras), so after every request i need to clear all temporary data. Is it normal usage to call soap_destroy() and soap_end() after every request? Because it seem's overkill to do it after each request. May be exists another option of proper usage?
DeviceBindingProxy::destroy()
{
soap_destroy(this->soap);
soap_end(this->soap);
}
class OnvifDeviceService : public Domain::IDeviceService
{
public:
OnvifDeviceService()
: m_deviceProxy(new DeviceBindingProxy)
{
soap_register_plugin(m_deviceProxy->soap, soap_wsse);
}
int OnvifDeviceService::getDeviceInformation(const Access::Domain::Endpoint &endpoint, Domain::DeviceInformation *information)
{
_tds__GetDeviceInformation tds__GetDeviceInformation;
_tds__GetDeviceInformationResponse tds__GetDeviceInformationResponse;
setupUserPasswordToProxy(endpoint);
m_deviceProxy->soap_endpoint = endpoint.endpoint().c_str();
int result = m_deviceProxy->GetDeviceInformation(&tds__GetDeviceInformation, tds__GetDeviceInformationResponse);
m_deviceProxy->soap_endpoint = NULL;
if (result != SOAP_OK) {
Common::Infrastructure::printSoapError("Fail to get device information.", m_deviceProxy->soap);
m_deviceProxy->destroy();
return -1;
}
*information = Domain::DeviceInformation(tds__GetDeviceInformationResponse.Manufacturer,
tds__GetDeviceInformationResponse.Model,
tds__GetDeviceInformationResponse.FirmwareVersion);
m_deviceProxy->destroy();
return 0;
}
}
To ensure proper allocation and deallocation of managed data:
soap_destroy(soap);
soap_end(soap);
You want to do this often to avoid memory to fill up with old data. These calls remove all deserialized data and data you allocated with the soap_new_X() and soap_malloc() functions.
All managed allocations are deleted with soap_destroy() followed by soap_end(). After that, you can start allocating again and delete again, etc.
To allocate managed data:
SomeClass *obj = soap_new_SomeClass(soap);
You can use soap_malloc for raw managed allocation, or to allocate an array of pointers, or a C string:
const char *s = soap_malloc(soap, 100);
Remember that malloc is not safe in C++. Better is to allocate std::string with:
std::string *s = soap_new_std__string(soap);
Arrays can be allocated with the second parameter, e.g. an array of 10 strings:
std::string *s = soap_new_std__string(soap, 10);
If you want to preserve data that otherwise gets deleted with these calls, use:
soap_unlink(soap, obj);
Now obj can be removed later with delete obj. But be aware that all pointer members in obj that point to managed data have become invalid after soap_destroy() and soap_end(). So you may have to invoke soap_unlink() on these members or risk dangling pointers.
A new cool feature of gSOAP is to generate deep copy and delete function for any data structures automatically, which saves a HUGE amount of coding time:
SomeClass *otherobj = soap_dup_SomeClass(NULL, obj);
This duplicates obj to unmanaged heap space. This is a deep copy that checks for cycles in the object graph and removes such cycles to avoid deletion issues. You can also duplicate the whole (cyclic) managed object to another context by using soap instead of NULL for the first argument of soap_dup_SomeClass.
To deep delete:
soap_del_SomeClass(obj);
This deletes obj but also the data pointed to by its members, and so on.
To use the soap_dup_X and soap_del_X functions use soapcpp2 with options -Ec and -Ed, respectively.
In principle, static and stack-allocated data can be serialized just as well. But consider using the managed heap instead.
See https://www.genivia.com/doc/databinding/html/index.html#memory2 for more details and examples.
Hope this helps.
The way memory has to be handled is described in Section 9.3 of the GSoap documentation.
I have a function that stores the value of an argument to an std::vector<v8::Local<v8::Value>> property of a C++ class exposes as an ObjectWrap like this:
NAN_METHOD(MyObject::Write) {
MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.This());
obj->data.push_back(info[0]);
}
However, when I try to read back the value from another C++ function, the value is lost, and becomes undefined.
I'm passing a number to MyObject::Write, and I can confirm info[0]->IsNumber() returns true before pushing it to the vector, however when reading it back, the value it not a number, and in fact returns false for all the types I tested using Is<Type> methods from v8::Value, but still returns true for BooleanValue().
My guess is that the variable is being garbage collected after MyObject::Write returns, however I have no idea how to prevent this from happening.
I'm currently trying to initialise the value as a Persistent value. I tried the following attempts without success:
Nan::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
Nan::Persistent<v8::Value> persistent(info[0]);
Nan::CopyablePersistentTraits::Copy(persistent, p);
And:
v8::Isolate *isolate = info.GetIsolate();
v8::Persistent<v8::Value, v8::CopyablePersistentTraits<v8::Value>> persistent(isolate, info[0]);
But getting tons of C++ errors.
I was running into problems untangling this mess myself. There's a lot of template stuff going on here that we both missed. Here was the solution I found most readable:
// Define the copyable persistent
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
// Create the local value
auto val = v8::Local<v8::Value>::New(
v8::Isolate::GetCurrent(), //< Isolate required
v8::Integer::New(v8::Isolate::GetCurrent(), v) //< Isolate required
);
// Reset() is a TEMPLATE FUNCTION, you have to template it with the same
// template type parameter as the v8::Local you are passing
p.Reset<v8::Value>(v8::Isolate::GetCurrent(), val); //< Isolate required
By "info" I assume you are referring to a v8::FunctionCallbackInfo reference. If so the above code would collapse to the following:
void SomeFunc(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
}
Because the persistent is now copyable you can do things like store it inside a standard library container. This was my use case. This is an example of storing a value in a vector:
std::vector<v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent> vect;
void AccumulateData(v8::FunctionCallbackInfo<v8::Value>& info) {
v8::CopyablePersistentTraits<v8::Value>::CopyablePersistent p;
p.Reset<v8::Value>(info[0]);
vect.push_back(p);
}
I hope this helps someone out there.
If you plan on storing v8 values in C++, you need to make them persistent instead of local so they're independent of handle scope and not garbage-collected when the handle scope is released.
Nan has version-independant wrappers for v8::Persistent and Co. Because of using inside std::vector<>, you'll also need to initialize Nan::Persistent with Nan::CopyablePersistentTraits so it becomes copyable (or make an own reference-counted container for it).