I'm in c++ and i'm writing a wrapper around a c library. The c library function i'm working with takes a type 'LDAPMessage **' as a parameter, where it will allocate the memory for you within the function. Normal usage looks like this:
LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me
Now I want to use unique_ptr in this case, with a custom deleter. Assume my deleter 'LDAPMessageDeleter' exists and works in the following.
unique_ptr<LDAPMessage*, LDAPMessageDeleter> msg_ptr(new LDAPMessage*);
c_lib_function(msg_ptr.get());
Though this compiles for me, i'm getting a seg fault. Could this code be at fault here? Is this correct usage of unique_ptr?
It might be easier to do e.g.
LDAPMessage* msg;
c_lib_function(&msg);
// Now we have out pointer (hopefully)
std::unique_ptr<LDAPMessage, LDAPMessageDeleter> msg_ptr(msg);
Of course, the LDAPMessageDeleter have to call the proper function to free the memory (e.g. free is the memory was allocated with malloc).
The problem with the code you show in the question, is that you try to create a pointer to a pointer, but don't make that first-level pointer actually point anywhere.
What you are effectively doing in your code is this:
LDAPMessage** msg;
c_lib_function(msg);
What's happening in the C library, is that the pointer is passed "by reference". Since C doesn't actually have proper references, it's kind of emulated by passing pointers. And passing a "reference" to a pointer is done by using the address-operator to pass the address of the pointer (which then becomes a pointer to the pointer).
Someone in the SO chat developed code valuely like this that I can no longer find:
//ptrptr magic
#include <memory>
template<class T, class deleter>
class ptrptr_type {
public:
ptrptr_type(std::unique_ptr<T, deleter>& ptr)
: uptr(&ptr), tptr(ptr.get()) {}
~ptrptr_type() {if (uptr->get()!=tptr) uptr->reset(tptr);}
operator T**() {return &tptr;}
private:
std::unique_ptr<T, deleter>* uptr;
T* tptr;
};
template<class T, class D>
ptrptr_type<T,D> ptrptr(std::unique_ptr<T, D>& ptr) { return {ptr};}
And the usage of this ptrptr is quite simple:
std::unique_ptr<LDAPMessage, LDAPMessageDeleter> my_ptr; //can be null or initialized, whichever
c_lib_function(ptrptr(my_ptr)); //use ptrptr(my_ptr) whenever you need a T**
That's it. Real simple. http://coliru.stacked-crooked.com/a/644ed001ffd547ae
What happens is ptrptr(my_ptr) creates a temporary ptrptr_type on the stack, which takes the pointer from the unique_ptr. The ptrptr then exposes a pointer to it's internal pointer, which the C function can freely modify. Afterwards, the temporary ptrptr_type is destroyed, and its destructor puts the new value for the pointer back into the original unique_ptr.
This isn't correct usage of the pointer-to-pointer. The function takes a pointer to uninitialized pointer and fills it. In your first example, this is a local variable. If you want it to be managed by unique_ptr, it should still be a local, just contained within the unique_ptr object.
LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me
std::unique_ptr< LDAPMessage, LDAPMessageDeleter > // This type contains a ptr
msg_ptr( msg ); // transfer ownership to C++
LDAPMessageDeleter should receive a LDAPMessage *, and pass it to the library to be released if necessary, otherwise pass to free().
Related
I have a function that creates a unique pointer to a dynamically allocated object "c".
template<typename T, typename... TArgs> void addComponent(TArgs&&... MArgs) {
if(!components.count(typeid(T))) {
T* c = new T(std::forward<TArgs>(MArgs)...);
c->entity = this;
std::unique_ptr<Component> uPtr{ c };
components[typeid(T)] = (std::move(uPtr));
c->init();
}
}
My understanding is that the unique_ptr takes control of the value of c because you can't have another pointer pointing too a unique_ptr, however c->init still works after c has been turned into a unique_ptr.
Why does this work? Does c somehow still point to the same new T() or is an entirely new object created?
The unique_ptr object stores a copy of the value of c. When the unique_ptr object is destroyed, its destructor will call delete on the stored pointer value.
The original variable c is not modified by the unique_ptr, and continues to point to the same object. It is perfectly fine to dereference it. The important thing is that since this pointer value will be deleted automatically by the unique_ptr, (1) you must not continue using its value after the unique_ptr's lifetime expires, and (2) you must not try to delete it manually.
Wrapping a raw pointer inside of a smart pointer does not change anything about the raw pointer. It still points at the same memory it was originally pointing at. The smart pointer is merely copying the pointer and then managing the pointed-at memory for you, delete'ing the memory when the smart pointer is destroyed or is otherwise assigned a different pointer.
FYI, it would be more safer and more efficient to use std::make_unique() instead of new, eg:
template<typename T, typename... TArgs>
void addComponent(TArgs&&... MArgs) {
if (!components.count(typeid(T))) {
auto c = std::make_unique<T>(std::forward<TArgs>(MArgs)...);
c->entity = this;
c->init();
components[typeid(T)] = std::move(c);
}
}
No new objects are created and nothing takes control over anything. You wrapped the raw pointer with the smart pointer, and should not use the raw pointer anymore.
The smart pointers only work if you don't work around them by using the raw pointer. But the value of the variable c doesn't change because of the assignment operator in std::unique_ptr constructor. It remains the same, and you as the programmer should be disciplined about not using it directly any more.
Good practice would be to have it as a temporary variable that disappears after it's wrapped into a smart pointer; or instead of new just use std::make_unique.
Consider my code below. My understanding of unique pointers was that only one unique pointer can be used to reference one variable or object. In my code I have more than one unique_ptr accessing the same variable.
It's obviously not the correct way to use smart pointers i know, in that the pointer should have complete ownership from creation. But still, why is this valid and not having a compilation error? Thanks.
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int val = 0;
int* valPtr = &val;
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(valPtr);
*uniquePtr1 = 10;
*uniquePtr2 = 20;
return 0;
}
But still, why is this valid
It is not valid! It's undefined behaviour, because the destructor of std::unique_ptr will free an object with automatic storage duration.
Practically, your program tries to destroy the int object three times. First through uniquePtr2, then through uniquePtr1, and then through val itself.
and not having a compilation error?
Because such errors are not generally detectable at compile time:
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(function_with_runtime_input());
In this example, function_with_runtime_input() may perform a lot of complicated runtime operations which eventually return a pointer to the same object valPtr points to.
If you use std::unique_ptr correctly, then you will almost always use std::make_unique, which prevents such errors.
Just an addition to Christian Hackl's excellent answer:
std::unique_ptr was introduced to ensure RAII for pointers; this means, in opposite to raw pointers you don't have to take care about destruction yourself anymore. The whole management of the raw pointer is done by the smart pointer. Leaks caused by a forgotten delete can not happen anymore.
If a std::unique_ptr would only allow to be created by std::make_unique, it would be absolutely safe regarding allocation and deallocation, and of course that would be also detectable during compile time.
But that's not the case: std::unique_ptr is also constructible with a raw pointer. The reason is, that being able to be constructed with a hard pointer makes a std::unique_ptr much more useful. If this would not be possible, e.g. the pointer returned by Christian Hackl's function_with_runtime_input() would not be possible to integrate into a modern RAII environment, you would have to take care of destruction yourself.
Of course the downside with this is that errors like yours can happen: To forget destruction is not possible with std::unique_ptr, but erroneous multiple destructions are always possible (and impossible to track by the compiler, as C.H. already said), if you created it with a raw pointer constructor argument. Always be aware that std::unique_ptr logically takes "ownership" of the raw pointer - what means, that no one else may delete the pointer except the one std::unique_ptr itself.
As rules of thumb it can be said:
Always create a std::unique_ptr with std::make_unique if possible.
If it needs to be constructed with a raw pointer, never touch the raw pointer after creating the std::unique_ptr with it.
Always be aware, that the std::unique_ptr takes ownership of the supplied raw pointer
Only supply raw pointers to the heap. NEVER use raw pointers which point to local
stack variables (because they will be unavoidably destroyed automatically,
like valin your example).
Create a std::unique_ptr only with raw pointers, which were created by new, if possible.
If the std::unique_ptr needs to be constructed with a raw pointer, which was created by something else than new, add a custom deleter to the std::unique_ptr, which matches the hard pointer creator. An example are image pointers in the (C based) FreeImage library, which always have to be destroyed by FreeImage_Unload()
Some examples to these rules:
// Safe
std::unique_ptr<int> p = std::make_unique<int>();
// Safe, but not advisable. No accessible raw pointer exists, but should use make_unique.
std::unique_ptr<int> p(new int());
// Handle with care. No accessible raw pointer exists, but it has to be sure
// that function_with_runtime_input() allocates the raw pointer with 'new'
std::unique_ptr<int> p( function_with_runtime_input() );
// Safe. No accessible raw pointer exists,
// the raw pointer is created by a library, and has a custom
// deleter to match the library's requirements
struct FreeImageDeleter {
void operator() (FIBITMAP* _moribund) { FreeImage_Unload(_moribund); }
};
std::unique_ptr<FIBITMAP,FreeImageDeleter> p( FreeImage_Load(...) );
// Dangerous. Your class method gets a raw pointer
// as a parameter. It can not control what happens
// with this raw pointer after the call to MyClass::setMySomething()
// - if the caller deletes it, your'e lost.
void MyClass::setMySomething( MySomething* something ) {
// m_mySomethingP is a member std::unique_ptr<Something>
m_mySomethingP = std::move( std::unique_ptr<Something>( something ));
}
// Dangerous. A raw pointer variable exists, which might be erroneously
// deleted multiple times or assigned to a std::unique_ptr multiple times.
// Don't touch iPtr after these lines!
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
// Wrong (Undefined behaviour) and a direct consequence of the dangerous declaration above.
// A raw pointer is assigned to a std::unique_ptr<int> twice, which means
// that it will be attempted to delete it twice.
// This couldn't have happened if iPtr wouldn't have existed in the first
// place, like shown in the 'safe' examples.
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
std::unique_ptr<int> p2(iPtr);
// Wrong. (Undefined behaviour)
// An unique pointer gets assigned a raw pointer to a stack variable.
// Erroneous double destruction is the consequence
int val;
int* valPtr = &val;
std::unique_ptr<int> p(valPtr);
This example of code is a bit artificial. unique_ptr is not usually initialized this way in real world code. Use std::make_unique or initialize unique_ptr without storing raw pointer in a variable:
unique_ptr <int> uniquePtr2(new int);
My following question is on memory management. I have for example an int variable not allocated dynamically in a class, let's say invar1. And I'm passing the memory address of this int to another classes constructor. That class does this:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
Should I delete ptoint? Because it has the address of an undynamically allocated int, I thought I don't need to delete it.
And again I declare an object to a class with new operator:
objtoclass = new ex1();
And I pass this to another class:
class ex2{
ex2(ex1* p_obj)
{
obj = p_obj;
}
ex1* obj;
};
Should I delete obj when I'm already deleting objtoclass?
Thanks!
Because it has the address of an undynamically allocated int I thought I don't need to delete it.
Correct.
Should I delete obj when I'm already deleting objtoclass?
No.
Recall that you're not actually deleting pointers; you're using pointers to delete the thing they point to. As such, if you wrote both delete obj and delete objtoclass, because both pointers point to the same object, you'd be deleting that object twice.
I would caution you that this is a very easy mistake to make with your ex2 class, in which the ownership semantics of that pointed-to object are not entirely clear. You might consider using a smart pointer implementation to remove risk.
just an appendix to the other answers
You can get rid of raw pointers and forget about memory management with the help of smart pointers (shared_ptr, unique_ptr).
The smart pointer is responsible for releasing the memory when it goes out of scope.
Here is an example:
#include <iostream>
#include <memory>
class ex1{
public:
ex1(std::shared_ptr<int> p_intvar1)
{
ptoint = p_intvar1;
std::cout << __func__ << std::endl;
}
~ex1()
{
std::cout << __func__ << std::endl;
}
private:
std::shared_ptr<int> ptoint;
};
int main()
{
std::shared_ptr<int> pi(new int(42));
std::shared_ptr<ex1> objtoclass(new ex1(pi));
/*
* when the main function returns, these smart pointers will go
* go out of scope and delete the dynamically allocated memory
*/
return 0;
}
Output:
ex1
~ex1
Should I delete obj when I'm already deleting objtoclass?
Well you could but mind that deleting the same object twice is undefined behaviour and should be avoided. This can happen for example if you have two pointers for example pointing at same object, and you delete the original object using one pointer - then you should not delete that memory using another pointer also. In your situation you might as well end up with two pointers pointing to the same object.
In general, to build a class which manages memory internally (like you do seemingly), isn't trivial and you have to account for things like rule of three, etc.
Regarding that one should delete dynamically allocated memory you are right. You should not delete memory if it was not allocated dynamically.
PS. In order to avoid complications like above you can use smart pointers.
You don't currently delete this int, or show where it's allocated. If neither object is supposed to own its parameter, I'd write
struct ex1 {
ex1(int &i_) : i(i_) {}
int &i; // reference implies no ownership
};
struct ex2 {
ex2(ex1 &e_) : e(e_) {}
ex1 &e; // reference implies no ownership
};
int i = 42;
ex1 a(i);
ex2 b(a);
If either argument is supposed to be owned by the new object, pass it as a unique_ptr. If either argument is supposed to be shared, use shared_ptr. I'd generally prefer any of these (reference or smart pointer) to raw pointers, because they give more information about your intentions.
In general, to make these decisions,
Should I delete ptoint?
is the wrong question. First consider things at a slightly higher level:
what does this int represent in your program?
who, if anyone, owns it?
how long is it supposed to live, compared to these classes that use it?
and then see how the answer falls out naturally for these examples:
this int is an I/O mapped control register.
In this case it wasn't created with new (it exists outside your whole program), and therefore you certainly shouldn't delete it. It should probably also be marked volatile, but that doesn't affect lifetime.
Maybe something outside your class mapped the address and should also unmap it, which is loosely analogous to (de)allocating it, or maybe it's simply a well-known address.
this int is a global logging level.
In this case it presumably has either static lifetime, in which case no-one owns it, it was not explicitly allocated and therefore should not be explicitly de-allocated
or, it's owned by a logger object/singleton/mock/whatever, and that object is responsible for deallocating it if necessary
this int is being explicitly given to your object to own
In this case, it's good practice to make that obvious, eg.
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
Note that making your local data member a unique_ptr or similar, also takes care of the lifetime automatically with no effort on your part.
this int is being given to your object to use, but other objects may also be using it, and it isn't obvious which order they will finish in.
Use a shared_ptr<int> instead of unique_ptr to describe this relationship. Again, the smart pointer will manage the lifetime for you.
In general, if you can encode the ownership and lifetime information in the type, you don't need to remember where to manually allocate and deallocate things. This is much clearer and safer.
If you can't encode that information in the type, you can at least be clear about your intentions: the fact that you ask about deallocation without mentioning lifetime or ownership, suggests you're working at the wrong level of abstraction.
Because it has the address of an undynamically allocated int, I
thought I don't need to delete it.
That is correct. Simply do not delete it.
The second part of your question was about dynamically allocated memory. Here you have to think a little more and make some decisions.
Lets say that your class called ex1 receives a raw pointer in its constructor for a memory that was dynamically allocated outside the class.
You, as the designer of the class, have to decide if this constructor "takes the ownership" of this pointer or not. If it does, then ex1 is responsible for deleting its memory and you should do it probably on the class destructor:
class ex1 {
public:
/**
* Warning: This constructor takes the ownership of p_intvar1,
* which means you must not delete it somewhere else.
*/
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
~ex1()
{
delete ptoint;
}
int* ptoint;
};
However, this is generally a bad design decision. You have to root for the user of this class read the commentary on the constructor and remember to not delete the memory allocated somewhere outside class ex1.
A method (or a constructor) that receives a pointer and takes its ownership is called "sink".
Someone would use this class like:
int* myInteger = new int(1);
ex1 obj(myInteger); // sink: obj takes the ownership of myInteger
// never delete myInteger outside ex1
Another approach is to say your class ex1 does not take the ownership, and whoever allocates memory for that pointer is the responsible for deleting it. Class ex1 must not delete anything on its destructor, and it should be used like this:
int* myInteger = new int(1);
ex1 obj(myInteger);
// use obj here
delete myInteger; // remeber to delete myInteger
Again, the user of your class must read some documentation in order to know that he is the responsible for deleting the stuff.
You have to choose between these two design decisions if you do not use modern C++.
In modern C++ (C++ 11 and 14) you can make things explicit in the code (i.e., do not have to rely only on code documentation).
First, in modern C++ you avoid using raw pointers. You have to choose between two kinds of "smart pointers": unique_ptr or shared_ptr. The difference between them is about ownership.
As their names say, an unique pointer is owned by only one guy, while a shared pointer can be owned by one or more (the ownership is shared).
An unique pointer (std::unique_ptr) cannot be copied, only "moved" from one place to another. If a class has an unique pointer as attribute, it is explicit that this class has the ownership of that pointer. If a method receives an unique pointer as copy, it is explicit that it is a "sink" method (takes the ownership of the pointer).
Your class ex1 could be written like this:
class ex1 {
public:
ex1(std::unique_ptr<int> p_intvar1)
{
ptoint = std::move(p_intvar1);
}
std::unique_ptr<int> ptoint;
};
The user of this class should use it like:
auto myInteger = std::make_unique<int>(1);
ex1 obj(std::move(myInteger)); // sink
// here, myInteger is nullptr (it was moved to ex1 constructor)
If you forget to do "std::move" in the code above, the compiler will generate an error telling you that unique_ptr is not copyable.
Also note that you never have to delete memory explicitly. Smart pointers handle that for you.
struct Temp
{
CString one;
CString two;
};
class Foo
{
public:
Temp obj;
void somewhere();
}
void Foo::somewhere()
{
void* pData = static_cast<void*>(&obj);
OwnMethod(pData); // void OwnMethod(void*);
}
The question is:
Should I create obj on heap or this situation isn't dangerous (passing local class objects pointer)?
If OwnMethod(pData) stores the pointer somwhere for later use, that later use is not possible anymore, once the object on which Foo::somewhere() is called is destroyed.
If OwnMethod(pData) only access the pointed to data, you are safe.
The member variable will last as long as the Foo object, so the pointer will be valid during the call to OwnMethod.
If that function stores a copy of the pointer somewhere, and something else uses that pointer later, then there is a danger that it might be accessed after the Foo (and therefore the pointer's target) have been destroyed. There are various ways to prevent that; as you say, one is to dynamically allocate the object, and then transfer or share ownership when it's passed to OwnMethod. Smart pointers, such as std::unique_ptr and std::shared_ptr, are a very good way to track ownership of dynamic objects.
Wow, a lot of issues.
A complex object should't be passed to anything taking a void*.
Who wrote OwnMethod?
Why doesn't it take a pointer of type Foo*?
In fact why doesn't it take a reference of type Foo&?
If OwnMethod() may be required to accept objects of several different types then it should take a base class pointer or reference and use polymorphism.
However as far as the lifetime arguments go - obj will exist as long as the wrapping class does, so if the pointer is not used beyond the scope of OwnMethod this is ok. If OwnMethod causes the pointer to be stored elsewhere beyond Foo's lifetime then you have an issue, and maybe obj should be allocated on the heap. (And it might not even be appropriate for it to be a member of Foo at all.)
I've got these lines:
typedef boost::shared_ptr<A> A_SPtr;
void *f(void* var){ ...
and i want to be able to do something like this:
A_SPtr instance = (void*)(var);
how can i do it?
Also, how can i cast the other way around meaning from the shared_ptr to void*?
Just cast pointers to shared pointers to and from void *.
shared_ptr to void *:
f (reinterpret_cast<void *>;(&A_SPtr));
void * back to shared_ptr:
A_SPtr instance = * reinterpret_cast(boost::shared_ptr<A>*)(var);
CAUTION: This passes a pointer to the shared pointer to the thread. This will not work if the shared pointer does not remain in existence through the life of the thread function – otherwise, the thread will have a pointer to an object (the shared pointer) that no longer exists. If you cannot meet that requirement, pass a pointer to a new shared_ptr and delete it when the thread is done with it. (Or use boost:bind which works with shared pointers directly.)
As long as you're sure it's okay to assume ownership of the void* passed to you in f, that the void* does in fact refer to an A object, and you know the correct way to clean up, then you can just go ahead and use a smart pointer to assume ownership:
typedef boost::shared_ptr<A> A_SPtr;
void *f(void *var){
A_SPtr instance(static_cast<A*>(var));
}
Edit: It's not clear from the question, but some comments indicate that your actually trying to pass a smart pointer through a 'generic' interface that uses void*. You do this the same way you'd do it for any type:
void *f(void *var){
A_SPtr *instance = static_cast<A_SPtr *>(var);
}
And you pass the pointer like:
A_SPtr a;
f(&a);
As with any pointer you must ensure that the object's lifetime is sufficient for the pointer to be valid when f receives it.