I wrote simple code to help me understand smart pointers:
string s = "str";
vector <unique_ptr<string>> pv ;
pv.push_back(unique_ptr<string>(&s));
cout<<*(pv[0])<<endl;
This code compiles fine, but gets me a runtime error:
str
* Error in `...': munmap_chunk(): invalid pointer: 0x00007ffd956e57e0 * Aborted (core dumped)
What happened and what have I done wrong?
In the std::unique_ptr's destructor it will call delete on the &s pointer which was not allocated via new.
Just use:
std::vector<std::string> vector;
vector.emplace_back("str");
std::cout << pv[0] << std::endl;
There's no need for std::unique_ptr<std::string> there.
Your string is being destructed twice - once when your pv goes out of scope and is deleted, freeing all its contained unique_ptr elements, and once when s goes out of scope.
To use a vector of unique pointers (or to use unique pointers in general), it is essential that they are not aliased. So you could write:
auto *s = new std::string("str");
pv.push_back(std::unique_ptr<std::string>(s));
// do not write "delete s" anywhere...
Or, simpler and safer:
pv.push_back(std::make_unique<std::string>("str")); // make_unique is C++14
Or even:
std::unique_ptr<std::string> p{new std::string("str")};
pv.push_back(std::move(p));
// Do not attempt to use p beyond this point.
Related
I was wondering if there is a way to access a data member within a struct that is being pointed to by a void*? What I'm trying to explain will hopefully be more apparent in my example code:
int main()
{
struct S
{
int val;
};
S s;
s.val = 5;
void* p;
p = malloc(sizeof(S));
*(struct S*) p = s;
std::cout<< *(struct S*)p.val << std::endl;
}
I have ran this exact code casting p as *(int*)p and it printed fine, however, using exact code above results in a compilation error. Haven't been able to find an example that quite accomplishes this task. Is it possible to access the data members of the struct after it is casted? why or why not? if so, how?
The . operator has higher precedence than a C-style cast. So *(struct S*)p.val is treated as *((struct S*)(p.val)), which doesn't make sense since p is a pointer and does not have members.
So you need parentheses to specify what you intended:
std::cout<< (*(struct S*)p).val << std::endl;
Or equivalently,
std::cout<< static_cast<S*>(p)->val << std::endl;
[But also: the statement *(struct S*) p = s; technically has undefined behavior, even though all most implementations will allow it. This is because C++ has rules about when an object is created, and there was no object of type S previously at that address, and assignment does not create an object except for some cases involving union members. A similar statement that does not have this problem would be new(p) S{s};.
Also also: use of malloc or void* is usually not a good idea in C++ in the first place. malloc should only be used when interfacing with a C library that requires it. Anything for which void* seems useful can probably be done more safely using templates. In a few cases a void* might be the only way to do something or "cleverly" avoid code duplication or something, but still use it sparingly and always with extreme caution.]
I stumbled upon this behaviour when using std::weak_ptr and std::make_shared and I found it a little weird. I am using C++11.
#include <iostream>
#include <memory>
int main()
{
std::weak_ptr<int> weak;
std::shared_ptr<int> shared {std::make_shared<int>(42)};
weak = shared;
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
weak = std::make_shared<int>(23);
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
return 0;
}
The first std::cout prints fine, the second gives me a segfault. I tried looking at the pages of std::weak_ptr and std::shared_ptr on cppreference but I still don't understand why this happens. Having to create a temporary object feels cumbersome to me, is this something that has been addressed in C++14 or is there something I am failing to see?
Thanks!
The weak_ptr can only be dereferenced after locking if a shared_ptr object still exists that's pointing to the same underlying object.
In your first part
std::shared_ptr<int> shared {std::make_shared<int>(42)};
weak = shared;
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
this is indeed the case. In the second part
weak = std::make_shared<int>(23);
std::cout << "Meaning of life: " << *weak.lock() << std::endl;
it is not the case, as the shared_ptr was a temporary object.
What you've encountered here is exactly what weak_ptr was built for - that it be valid only as long as some other shared_ptr points to the same underlying object. That is its purpose:
std::weak_ptr is a smart pointer that holds a non-owning ("weak") reference to an object that is managed by std::shared_ptr... If the original std::shared_ptr is destroyed at this time, the object's lifetime is extended until the temporary std::shared_ptr is destroyed as well.
This is due to the fact that you create a temporary shared pointer and assign it to a weak pointer right away in this line:
weak = std::make_shared<int>(23);
After the assignment operator ends, the temporary shared pointer is destructed, the reference count reaches 0 (since weak pointers do not increase the reference counter) and hence, the resource on the heap is deleted.
Suppose I have a following code:
#include <iostream>
#include <deque>
#include <memory>
struct Test
{
int test;
};
int main(int, char**)
{
std::deque<std::unique_ptr<Test>> deque;
deque.push_back(std::unique_ptr<Test>(new Test{10}));
auto start = deque.begin();
std::cout << start->test << std::endl; // <- compilation error
std::cout << (start.operator->())->operator->()->test << std::endl; // <- OK
}
Why is smart-pointer treated as if it would be regular pointer object, although it is not (as far, as I understand)? From what I know, operator->() should recur until it reaches T*.
Here are some related questions on how arrow overloading works and that we need to dereference twice instead of an arrow.
For an iterator it, the expression it->m is equivalent to (*i).m, technically it means that the iterator's operator-> returns a raw pointer to the contained object. In your case it means it returns a raw pointer to the unique_ptr. A final operator-> is applied to that and you end up with a reference to the contained object. This is why no further chaining of operator-> occurs.
The arrow operator is overloaded for unique_ptr. Because you have an iterator, you are dereferencing to a unique_ptr, not the object owned by it. Therefore, you need to dereference twice.
std::cout << (*start)->test << std::endl;
Smart pointer like std::unique_ptr are implemented to store a pointer and behave like a C pointer, while iterators also are pointers themselves.
So why you need to dereference twice? Simply because you have a pointer to pointer to Test.
Its exactly the same as if you have a container of plain pointers:
std::deque<Test*> dq;
dq.push_back(new Test{10});
auto start = dq.begin();
std::cout << (*start)->test << std::endl;
I have been working on std::unique_ptr s but confused at some point about its semantics. From the documentation,
No two unique_ptr instances can manage the same object
But, even tough it is most probably a silly example, consider such a code.
std::unique_ptr<int> a(new int(10));
std::unique_ptr<int> b = std::unique_ptr<int>(a.get());
std::cout << *b << std::endl;
*a = 5;
std::cout << *b;
a and b is managing the same object here, and the output is 10 5. And of course I am getting an assertion failure error at the end on debug mode due to two unique ptrs trying to destruct same object at the end of scope.
I know it is silly and such usage is not advised, but I came across to this when it was not very obvious ( a class member calling another etc. ) and the assertion failure was the thing I started with.
My question is what the above sentence exactly means: it is posed by the standard and a decent compiler shouldnt allow you to do it (i am on vs2013 btw) or you must do it that way ( never cause two unique_ptrs point to same object) ( unlikely since the purpose of unique_ptrs is to make us less worried i suppose.) Or I should never use anything about raw pointers ( a.get() ) when unique_ptr s are involved.
Your last sentence is correct. As soon as you use raw pointers with a.get() as in the line below, you have thrown away all the promises that std::unique_ptr make to you.
std::unique_ptr<int> b = std::unique_ptr<int>(a.get());
The correct semantic to preserve the uniqueness while converting to a raw pointer would be to use a.release().
std::unique_ptr<int> b = std::unique_ptr<int>(a.release());
Of course, you would normally just use assignment or initializatoin with std::move if you were moving ownership between two std::unique_pointer instances, as given by the documentation. Either of the two lines below should be valid.
std::unique_ptr<int> b(std::move(a));
std::unique_ptr<int> b = std::move(a);
To make the std::move semantics more clear, consider the following test program.
#include <stdio.h>
#include <memory>
#include <stdlib.h>
int main(){
std::unique_ptr<int> a(new int(10));
printf("%p\n", a.get());
std::unique_ptr<int> b(std::move(a));
printf("%p\n", a.get());
printf("%p\n", b.get());
}
On my system, the output is the following. Observe that the first line and the last line match.
0x1827010
(nil)
0x1827010
I ran into a problem with a dirty shutdown of my program, because of a shared pointer. I found a solution, but I'm not sure, if I have the right answer.
This is the minimalistic example:
double var;
boost::shared_ptr<const double> ptr1 (&var); // creates an invalid pointer on program exit
boost::shared_ptr<const double> ptr2 (new double); // works fine
int main (int argc, char **argv)
{
return 0;
}
Here is my answer which I would like to varify:
In the case of ptr1 the pointed-to object will be deleted before the pointer, which then points to an invalid address. But in the case of ptr2 the "smartness" of the shared pointer handles the issue above.
True?
Small extra question:
Is there a way to make ptr1 work (I tried reset()) or is that bad programming practice (if so why)?
Thanks for the clarification!
in the first case, the pointer isn't dynamically allocated, so the shared_ptr should not attempt to destroy the underlying object. that can be done by using a custom no-op deleter functor:
http://www.boost.org/doc/libs/1_51_0/libs/smart_ptr/sp_techniques.html#static