I accidentally found this issue on C++, but totally had no idea how it was happened, please check the code snippet below:
int main() {
int *aptr = new int(20); //Declare an integer space with 20, and aptr points to it
shared_ptr<int> a(aptr); //Declare a shared_ptr to points where aptr points
stringstream ss;
ss << a;
const char *chstr = ss.str().c_str(); // Save the address as string
void *address;
sscanf(chstr, "%p", (void **)&address); // Convert string back to pointer
a = NULL; // Free the shared pointer
cout << *reinterpret_cast<int*>(address) << endl; // Output: 0, 20 has gone
return 0;
}
Is there anybody could tell me why the address has been freed ?
I didn't manipulate the original integer pointer "aptr", but somehow it's space has disappeared, because of the shared_ptr ?
I'd like to know how it was happend, thank you all !
The whole purpose behind std::shared_ptr is to take ownership of the dynamically-allocated object. Once std::shared_ptr takes ownership of a dynamically-allocated object, via either std::make_shared or by directly assigning a pointer to it, std::shared_ptr owns it, lock stock and barrel. Owning it means automatically deleteing the dynamically scoped object when the last reference to the dynamically-scoped object goes out of scope. That's what the shared_ptr is for, and nothing else.
a = NULL;
This used shared_ptr's assignment operator to replace the shared_ptr-owned pointer(*). Since the original dynamically-scoped object that the shared_ptr owns has no other reference, the shared_ptr deletes the original pointer that was used to construct it.
The fact that you still have the original, native pointer to the int is irrelevant. shared_ptr doesn't care. The whole thing gets deleted.
If you don't want shared_ptr to delete whatever you newed, and use a native pointer for, either don't use shared_ptr, or make sure one is still around as long as you still need to use a native pointer to the underlying object.
(*) This actually implicitly constructs another shared_ptr, and uses the regular assignment operator.
This code does not compile in g++ 4.2.1 (but as Sam mentioned, it complies with version 6):
Georgioss-MacBook-Pro:~ gsamaras$ g++ -Wall main.cpp
main.cpp:17:11: error: no viable overloaded '='
a = NULL; // Free the shared pointer
~ ^ ~~~~
By the way, you should use shared_ptr::reset:
In all other cases, the shared_ptr acquires ownership of p with a use
count of 1, and -optionally- with del and/or alloc as deleter and
allocator, respectively.
Additionally, a call to this function has the same side effects as if
shared_ptr's destructor was called before its value changed (including
the deletion of the managed object if this shared_ptr was unique).
Also check string::c_str. You are saving the address of a temporary string, which is the start of something bad.
Related
I have unique_ptr and a row pointer that the unique_ptr points to. How do I call release for unique_ptr using only row pointer rowPtr?
#include <iostream>
#include <memory>
int main()
{
std::unique_ptr<int> uniqPtr = std::make_unique<int>(2);
int* rowPtr = uniqPtr .get();
// call .release for uniqPtr using only rowPtr
return 0;
}
UPD:
I will clarify the question. I need uniqPtr to become empty using only rowPtr.
How do I call release for unique_ptr using only row pointer rowPtr?
You cannot. You can only release a unique pointer by calling the release member function on the unique pointer. You cannot use, nor do you need, the bare pointer to do that.
You don't. Raw pointers do not participate in ownership. Nor shall they.
When you call get you are explicitly saying: "I want only a raw pointer. I do not want to interfere with ownership of the managed pointer".
You can either use int *p = uniqPtr.release() to get the pointer without destroying it. p points still to a valid memory, but uniqPtr is no longer managing it.
You can also use uniqPtr.reset(nullptr) which would destroy the object and resets the unique_ptr to a nullptr. In this case ptr is no longer pointing to the object and the memory of that object has been freed.
In any case you can not use the raw pointer, managed by uniqPtr, to change the state of the unique_ptr object, because the raw pointer doesn't have any association with it, it's just managed by it.
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);
I am just learning about smart pointers, and I am having trouble assigning a pre-existing location of a variable to the standard library's shared pointer.
For example, lets say you have an int x, which you do not know the value of. With normal pointers, I just did
int* ptr;
ptr = &x;
I tried both that with shared pointers, and
std::tr1::shared_ptr<int> ptr;
ptr = std::make_shared<int> (&x)
So i'm fairly lost as to how to do it.
You wouldn't (usually) make a smart pointer point to an existing variable. A smart pointer manages the lifetime of a dynamically allocated object, deleting it after use; pointing it to something that wasn't dynamically allocated will cause an error if it tries to delete it.
You would usually use new or make_shared to create an object, and create or assign a smart pointer with the result of that:
std::shared_ptr<int> ptr(new int(42)); // Create a new pointer to manage an object
ptr.reset(new int(66)); // Reset to manage a different object
ptr = std::make_shared<int>(53); // Use `make_shared` rather than `new`
make_shared is usually preferable to new, since it makes better use of memory and gives stronger exception-safety.
Shared pointers are used to manage dynamically allocated memory and more precisely, they manage the ownership for this memory.
Basically, a smart pointer is a materialization of the Ressource Acquisition Is Initialization, or RAII. I strongly suggest you take a look at this principle, as it is extremely useful for managing resource ownership (basically, each time you need to acquire a resource, and release it, be it memory, a database connection, a file handler, a mutex, etc.).
What it does is basically guarantee that while someone points at the dynamically allocated memory it manages, then this memory will be available, and as soon as the last (smart) pointer to this memory goes out of scope, then delete is called.
Then, it makes no sense to use smart pointers with variable that have automatic storage duration (i.e. that are removed when they go out of scope or when the object they're member of goes itself out of scope or is deleted (if it was new'd).
You should not create a smart pointer pointing to an object that is not dynamically allocated. Otherwise the smart pointer may try to delete the allocated memory which in turn will cause an error.
as soon as the reference counter of the shared_ptr reaches zero, the object will be deleted by the last shared_ptr. with smart pointers you can specify the function which shall delete that object.
the Deleter is a simple function (defaults to the usual operator delete) that has to be bound to the smart pointer, either statically via template parameter (see unique_ptr) or dynamically via constructor parameter (see shared_ptr).
// dynamically via shared_ptr:
// shared_ptrs share the pointer to the Deleter
// because they already share a common data structure for reference counting.
auto ignore = [](int* o){
std::cout<<"i will refuse to delete this object: " << o << "\n";
std::cout<<"not my responsibility." <<std::endl;
};
std::shared_ptr<int> sptr(&x,ignore);
//statically via unique_ptr:
// actually, the unique_ptr is as data structure not more than a regular pointer.
// but a pointer with special copy-constructor and destructor,
// which will most likely be inlined.
// there is no space to store a reference to a Deleter dynamically.
struct IgnorantDeleter{
void operator()(int* o){
std::cout<<"who ate my cake? " << o << "\n";
std::cout<<"but i baked it." <<std::endl;
}
};
std::unique_ptr<int,IgnorantDeleter> uptr(&x);
Simple question here: are you allowed to explicitly delete a boost::shared_ptr yourself? Should you ever?
Clarifying, I don't mean delete the pointer held by the shared_ptr. I meant the actual shared_ptr itself. I know most people suggest to not do it, so I was just wondering if it's OK to explicitly do it.
Your question isn't clear. If you've allocated a shared_ptr dynamically then you're certainly allowed to delete it whenever you want.
But if you're asking whether you're allowed to delete whatever object is being managed by the shared_ptr, then the answer is ... it depends. If shared_ptr::unique returns true, then calling shared_ptr::reset will delete the managed object. However, if shared_ptr::unique returns false, it means there are more than one shared_ptrs sharing ownership of that object. In this case a call to reset will only result in the reference count being decremented by 1, actual deletion of the object will take place when the last shared_ptr managing that object either goes out of scope or is itself reset.
EDIT:
After your edit, it seems you are asking about deleting a dynamically allocated shared_ptr. Something like this:
auto sp = new boost::shared_ptr<int>( new int(42) );
// do something with sp
delete sp;
This is allowed and will work as expected, although it would be an unusual use case. The only caveat is that if in between the allocation and deletion of sp you create another shared_ptr that shares ownership of the object, deleting sp will not result in deletion of the object, that will only happen when the reference count for the object goes to 0.
[Edit: you can delete a shared_ptr if and only if it was created with new, same as any other type. I can't think why you'd create a shared_ptr with new, but there's nothing stopping you.]
Well, you could write delete ptr.get();.
Doing so leads almost inevitably to undefined behavior either when the other shared owners use their shared_ptr to access the now-deleted object, or the last shared_ptr to the object is destroyed, and the object gets deleted again.
So no, you shouldn't.
The purpose of shared_ptr is to manage an object that no one "person" has the right or responsibility to delete, because there could be others sharing ownership. So you shouldn't ever want to, either.
If you want to simulate the count decrement, you can do it manually on the heap like so:
int main(void) {
std::shared_ptr<std::string>* sp = new std::shared_ptr<std::string>(std::make_shared<std::string>(std::string("test")));
std::shared_ptr<std::string>* sp2 = new std::shared_ptr<std::string>(*sp);
delete sp;
std::cout << *(*sp2) << std::endl; // test
return 0;
}
Or on the stack using std::shared_ptr::reset() like so:
int main(void) {
std::shared_ptr<std::string> p = std::make_shared<std::string>(std::string("test"));
std::shared_ptr<std::string> p2 = p;
p.reset();
std::cout << *p2 << std::endl; // test
return 0;
}
But it's not that useful.
You cannot force its reference count to zero, no.
Think about what would be required for that to work. You would need to go to each place the shared_ptr is used and clear it.
If you did force the shared pointer to delete and set it to NULL, it would be just like a weak_ptr. However, all those places in the code using that shared_ptr are not ready for that and expect to be holding a valid pointer. They have no reason to check for NULL, and so those bits of code would crash.
Expliticly deleting comes in handy in some (very?) rare cases.
In addition to explicitly deleting, sometimes you HAVE to explicitly destruct a shared pointer when you are 'deleting' it!
Things can get weird when interfacing with C code, passing a shared_ptr as an opaque value.
For example I have the following for passing objects to and from the Lua scripting language which is written in C. (www.lua.org)
static void push( lua_State *L, std::shared_ptr<T> sp )
{
if( sp == nullptr ) {
lua_pushnil( L );
return;
}
// This is basically malloc from C++ point of view.
void *ud = lua_newuserdata( L, sizeof(std::shared_ptr<T>));
// Copy constructor, bumps ref count.
new(ud) std::shared_ptr<T>( sp );
luaL_setmetatable( L, B::class_name );
}
So thats a shared_ptr in some malloc'd memory. The reverse is this... (setup to be called just before Lua garbage collects an object and 'free's it).
static int destroy( lua_State *L )
{
// Grab opaque pointer
void* ud = luaL_checkudata( L, 1, B::class_name );
std::shared_ptr<T> *sp = static_cast<std::shared_ptr<T>*>(ud);
// Explicitly called, as this was 'placement new'd
// Decrements the ref count
sp->~shared_ptr();
return 0;
}
Object object = *(queue.dequeue());
queue is a QQueue<Object*>. i'm concerned that the dequeued pointer is deleted before i dereference it. of course i can access object's data but that doesn't mean anything. doing it all in one line like this is convenient (i don't want a pointer because i want object to be deleted automatically when it goes out of scope) but if it's not safe then i can't do it. please advise. thanks.
It isn't immediately unsafe per se, but chances are you'll be using it wrong.
All your code does is make a copy of the element pointed to by the last element of queue. By dequeuing the element, you lose the pointer to it, and you now have no way of freeing that original object in case it was dynamically constructed.
Correct example (no dynamic objects, no leak):
QQueue<Foo*> q;
{
Foo a;
q.enqueue(&a);
Foo b = *q.dequeue();
}
Broken example (dynamic object leaked):
QQueue<Foo*> q;
q.enqueue(new Foo); // eeew, naked "new" in C++...
Foo c = *q.dequeue();
// now the newed element is leaked
You're right that c is safely destroyed at the end of its scope, but you're leaking the orginal, new'ed object, to which you have no pointer or reference now.