I have a class that has a setter method which takes a unique_ptr as an argument. That unique_ptr is saved as a class member.
class TestClass {
std::unique_ptr<Tester> sp;
void setTester_Way1(std::unique_ptr<Tester> te) {
auto deleter=std::move(sp);
sp=std::move(te);
}
void setTester_Way2(std::unique_ptr<Tester> te) {
sp=std::move(te);
}
};
Which way is the correct way to set the smart pointer? Does Way2 leak the original pointer of sp?
Way2 is fine, when you assign to a unique_ptr any existing owned pointer will be safely deleted.
As Chris Drew said Way2 is fine. One thing though is that unique_ptr is not copyable/assignable so the only ways to pass a unique_ptr is by reference, r-value reference or by value with move(). Trying to do:
int main()
{
TestClass t;
auto p = std::make_unique<int>(10);
t.setTester_Way2(p);
}
Will fail to compile. Although you can move() p into the function(example).
If you change setTester_Way2() to void setTester_Way2(std::unique_ptr<int>& te) then it will compile. If you change the function to take an rvalue reference and std::move() the pointer into the funcnction:
class TestClass {
std::unique_ptr<int> sp;
public:
void setTester_Way1(std::unique_ptr<int> te) {
auto deleter=std::move(sp);
sp=std::move(te);
}
void setTester_Way2(std::unique_ptr<int>&& te) {
sp=std::move(te);
}
};
int main()
{
TestClass t;
auto p = std::make_unique<int>(10);
t.setTester_Way2(std::move(p));
}
Then it will also compile.
Related
i dont know why the unique pointer implement is very very easy ,but unique pointer can destruct the object when this pointer out of scope.
There is anything else i dont know?
i write a test: I find when I call class's contruct fuction like unique pointer, it will call T's destruct automately.
But when I call the function ,it will not call T's destruct automately.
Now my question changes,i wonder why class's contruct fuction can do that ? It's RTTI? When MyPointer object destory itself?
#include<memory>
#include<iostream>
class T{
public:
T(){
std::cout<<"construct T"<<std::endl;
};
~T(){
std::cout<<"destruct T"<<std::endl;
}
};
void fun(T *t){};
template<class T>
class MyPointer
{
private:
T *__contain;
public:
MyPointer(T *t):__contain(t){
}
~MyPointer(){
delete __contain;
};
};
int main(){
using namespace std;
{
unique_ptr<T> a(new T) ;//call T' construct
unique_ptr<T> *pa=new unique_ptr<T>(new T);// dont call T' destruct
MyPointer<T> mypointer(new T);//call T' construct
T *t=new T; //dont call T' destruct
fun(new T); //dont call T' destruct
}
}
A unique_ptr is not much more than
template < typename T >
class unique_ptr
{
public:
unique_ptr(T* p)
:value(p)
{}
~unique_ptr()
{
delete value;
}
private:
T* value;
};
There are a lot of other methods and constructors required for a complete implementation (especially the move constructor and assignment operator) but I've omitted them as they're not relevant to your question.
When you write:
void foo()
{
unique_ptr<int> p(new int(5));
}
The new int pointer is stored in the unique_ptr object p and at the end of the foo function p is destructed which calls the unique_ptr destructor which deletes the pointed to int. Any locally allocated object will be destructed when it goes out of scope. A unique_ptr is no different it deletes the pointer it owns in its destructor. Note that if you allocate a unique_ptr with new it is the same as any other object it wont be destroyed until you call delete:
void foo()
{
unique_ptr<int>* p = new unique_ptr<int>(new int(5));
}
It's safe to say that you should pretty much never be using a dynamically allocated unique_ptr as that would defeat the purpose of using unique_ptr.
To clarify this code:
void foo()
{
unique_ptr<int> p(new int(5));
unique_ptr<int>* q = new unique_ptr<int>(new int(5));
}
Will make the compiler generate something like this:
p = stack_allocate(sizeof(unique_ptr<int>));
temp = stack_allocate(sizeof(int*));
*temp = heap_allocate(sizeof(int));
**temp = 5;
p->construct(*temp);
stack_free(temp);
q = stack_allocate(sizeof(unique_ptr<int>*));
*q = heap_allocate(sizeof(unique_ptr<int>));
temp = stack_allocate(sizeof(int*));
*temp = heap_allocate(sizeof(int));
**temp = 5;
(*q)->construct(*temp);
stack_free(temp);
stack_free(q);
p->destruct();
stack_free(p);
(In reality some of the variables are probably just held in registers not on the stack but this is generally how the generated code looks). Notice that all the stack allocated variables are automatically destroyed and deallocated whereas those created by new on the heap aren't.
Below is a simplified example of the code I'm working on. There's a function that takes class A pointer as an argument. I want to pass a pointer that has been initialized as nullptr. Without initializing it to some garbage temporary value first, is it possible to pass the nullptr?
class A
{
// stuff
};
class B
{
public:
A* pA1;
A objA;
std::vector<A*> vecB;
B() : pA1 (nullptr) { vecB.push_back(&objA); }
};
void function(A* p);
A* pA2;
int main()
{
B objB;
pA2 = objB.vecB[0];
function(objB.pA1);
return 0;
}
void function(A* p)
{
p = pA2;
}
In a comment, you said:
The point of the function is to make this happen: objB.pA1 = pA2
I think what you need to do is pass a reference to the pointer, instead of passing a pointer by value. Use:
void function(A*& p) // The argument type needs to be "A* &", not "A*"
{
// Now, the change will be visible in the calling program.
p = pA2;
}
Yes. Any raw pointer type can be assigned and therefore initialised with the nullptr value. Example:
static A* pA2 = nullptr;
aschepter has given me the answer in a comment, thank you very much.
void function(A* p)
should be
void function(A*& p)
This code below will result in memory loss because rA is initialized as invalid when it is constructed. When can I do to fix this problem?
Use shared_ptr or hope for future compiler versions to catch this bad code?
#include <memory>
using namespace std;
struct A {};
void use(const A& a) {};
unique_ptr<A> foo()
{
unique_ptr<A> pa(new A());
return pa;
}
int main()
{
const A& rA = *foo(); // rA is unusable, initialized with invalid reference (invalidated by destruction of temporary unique_ptr returned from foo)
use(rA);
}
Rewrite your main as:
int main()
{
auto a = foo();
use(*a);
}
As an aside I would rewrite foo as:
std::unique_ptr<A> foo()
{
return std::make_unique<A>();
}
When you return objects by value you return a temporary that will get destroyed immediately unless it is copied or bound to a variable from the caller's side.
What you are doing wrong is binding a reference to something the returned temporary object contains and not the returned object itself. By the time you access the thing you have bound a reference to it has been deleted by the temporary object's destructor when it was destroyed.
To illustrate what you are doing wrong I have written an equivalent example using a std::vector and binding a reference to one of its elements:
void use(const int& a) {}
std::vector<int> foo()
{
return {1, 2, 3};
}
int main()
{
const int& rA = foo()[0]; // bind to an element
// the vector itself is destroyed by the time we get here
use(rA); // whoops using a reference to an element from a destroyed vector
}
I have this code:
struct Base {};
struct Derived : public Base {
int somedata;
};
std::unique_ptr<Base> createTemporary() {
return std::make_unique<Derived>(); // This code has been simplified
}
template<typename T>
T& convertValueTo(std::unique_ptr<Base>&& obj) {
return static_cast<T&>(*obj);
}
int main() {
int data = convertValueTo<Derived>(createTemporary()).somedata;
return 0;
}
I designed the convertValueTo templated function to return the asked type of the object and mostly for function calls like
auto some_value = convertValueTo<Something_Else>(createTemporary()).a_member_variable;
Now I'm wondering.. is there a safer way to do this? If someone were to use the returned reference from convertValueTo, the temporary will be destroyed as soon as the line expression ends right?
My goal is:
Allow the use of a temporary and destroy it as soon as possible if the reference is not stored (as above)
Allow a safe reference binding to a valid object in case someone wants to
Convert to a unique_ptr of the required type. Then it is clear who has ownership of the dynamically created object, namely the unique_ptr returned from the conversion function. As soon as you create an lvalue reference to the dynamically created object, there will be the possibility that the reference survives the lifetime of your object.
#include <memory>
struct Base {};
struct Derived : public Base {
int somedata;
};
std::unique_ptr<Base> createTemporary() {
return std::make_unique<Derived>(); // This code has been simplified
}
template<typename T>
std::unique_ptr<T> convertValueTo(std::unique_ptr<Base>&& obj) {
auto ptr = obj.release ();
return std::unique_ptr<T> { static_cast<T*>(ptr) };
}
int main() {
int data = convertValueTo<Derived>(createTemporary())->somedata;
return 0;
}
I am exploring the use of std::function and std::bind. I see that you can bind a member function, for example:
class A{
int c_ = 10;
public:
int add(int a, int b){
return a + b + c_;
}
};
int main(){
A* p_a = new A;
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
delete p_a;
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
}
Is there a way to detect if p_a has been deleted?
My solution to do this is having a wrapper class that holds the function and a weak_ptr to the object. I am just wondering if there is a more elegant way to do this.
std::bind can accept smart pointers, so you can simply pass std::shared_ptr<A> to it.
std::shared_ptr<A> p_a(new A);
std::function<int()> f = std::bind(&A::add, p_a, 1, 1);
Note, that the functor will own the object: the object will live as long as the functor lives. If you don't want such behavior, then your solution with a weak_ptr wrapper is nice.
struct A{
int c_ = 10;
int add(int a, int b){
return a + b + c_;
}
};
template<class T>
std::weak_ptr<T> weak( std::shared_ptr<T> const& sp ) { return {sp}; }
int main(){
auto p_a = std::make_shared<A>();
std::function<int()> f = [w_a = weak(p_a)]() {
if (auto p_a = w_a.lock())
return p_a->add(1,1);
throw w_a;
}
printf("%i\n", f()); // yields "12" (1 + 1 + 10)
p_a.reset();
try {
printf("%i\n", f()); // yields derpy numbers, no errors thrown.
} catch( std::weak_ptr<A> wp ) {
printf("object deleted\n");
}
}
live example.
in general, in C++ you don't pay for what you don't use.
Tracking the lifetime of objects has a cost. If you want to track the lifetime of objects, you can use a shared_ptr or weak_ptr to the (free-store) allocated object, or use a weak_ptr to a shared_ptr (uniquely) owned by the object to indicate its lifetime is over.
The above is an implementation using C++14 lambdas to capture the object's shared pointer as a weak ptr, and give defined behavior (a throw of a copy of said weak pointer) if it has been deleted.
A lifetime token looks like:
using lifetime_token = std::weak_ptr<void>;
struct has_lifetime {
has_lifetime():token(std::make_shared<char>()) {}
has_lifetime(has_lifetime const&o):has_lifetime() {} // not default
lifetime_token get_lifetime() const {
return token;
}
private:
std::shared_ptr<void> token;
};
inheriting from has_lifetime gives you a get_lifetime() member that exists for as long as you do (it is destroyed by your destructor, and can no longer be .lock()d).
This is an easier pattern to follow if you cannot modify the ownership semantics of the original class. Simply .lock() the lifetime_token of the object to determine if it is still alive.