How to extend the lifetime of a local variable or the proper use of references

I was developing some class and came across this question. I have the following class:

struct A { int *p; A() { p = new int(1); cout << "ctor A" << endl; } A(const A& o) { cout << "copy A" << endl; p = new int(*(op)); } A(A&& o) { cout << "move A" << endl; p = std::move(op); op = NULL; } A& operator=(const A& other) { if (p != NULL) { delete p; } p = new int(*other.p); cout << "copy= A" << endl; return *this; } A& operator=(A&& other) { p = std::move(other.p); other.p = NULL; cout << "move= A" << endl; return *this; } ~A() { if(p!=NULL) delete p; p = NULL; cout << "dtor A" << endl; } }; 

And the following class that has A as a property:

 class B { public: B(){} A myList; const A& getList() { return myList; }; }; 

And this function, which checks a certain value of a variable and returns different objects in different cases:

 B temp; A foo(bool f) { A a; *ap = 125; if (f) return a; else { return temp.getList(); } } 

Now I want to use this function as follows:

 A list1 = foo(true); if(list1.p != NULL) cout << (*list1.p) << endl; cout << "------"<<endl; A list2 = foo(false); if (list2.p != NULL) cout << (*list2.p) << endl; 

The purpose of this situation:

The foo function should return (or move) without copying any local object with changes in p if the argument is true , or should return the property of the global variable temp without calling copy constructors A (i.e. return the link myList ), and also should not grab myList from B (it should not destroy myList from B , so std::move cannot be used) if the argument is false .

My question is:

How do I change the function foo to follow the upper conditions? The current implementation of foo works correctly if true and moves this local variable, but if false it calls the copy constructor for list2 . Another idea was to somehow extend the lifetime of the local variable, but adding a const link didn't work for me. Current Output:

 ctor A ctor A move A dtor A 125 ------ ctor A copy A dtor A 1 dtor A dtor A dtor A 
+8
c ++ reference c ++ 11 move object-lifetime
source share
3 answers

If you can change B to

 class B { public: B(){} std::shared_ptr<A> myList = std::make_shared<A>(); const std::shared_ptr<A>& getList() const { return myList; }; }; 

then foo could be:

 B b; std::shared_ptr<A> foo(bool cond) { if (cond) { auto a = std::make_shared<A>(); *a->p = 125; return a; } else { return b.getList(); } } 

Demo

Exit

 ctor A ctor A 125 ------ 1 dtor A dtor A 
+3
source share

The simplest solution is probably to use std::shared_ptr , as in Jarod42's answer. But if you want to avoid smart pointers, or if you cannot change B , you can probably create your own wrapper class, which may or may not have A std::optional can be quite convenient for this:

 class AHolder { private: std::optional<A> aValue; const A& aRef; public: AHolder(const A& a) : aRef(a) {} AHolder(A&& a) : aValue(std::move(a)), aRef(aValue.value()) {} const A* operator->() const { return &aRef; } }; 

The class contains optional to own A , if necessary, and you can use move-semantics to move it. The class also contains a link (or pointer) that either refers to the contained value or refers to another object.

You can return this from foo :

 AHolder foo(bool f) { A a; *ap = 125; if (f) return a; else { return temp.getList(); } } 

And the caller can access the contained link:

  auto list1 = foo(true); if(list1->p != nullptr) cout << (*list1->p) << endl; cout << "------"<<endl; auto list2 = foo(false); if (list2->p != nullptr) cout << *list2->p << endl; 

Live demo .

If you do not have access to std::optional , there is boost::optional or you can use std::unique_ptr due to the allocation of dynamic memory.

+2
source share

Your foo function returns an instance of A, not a link (or pointer), so you cannot access the contents of B.myList without copying or moving.

To gain this access, you must either use smart pointers (like Jarod42) or just plain pointers like this:

 B temp; A* foo(bool f) { if (f) { A* ptr = new A; *ptr->p = 125; return ptr; } else { return &temp.getList(); } } 

However, this specific code will not work. Cz.getList () returns a const reference, but foo returns a non-const pointer (it can, but should not be dirty, cracked with const_cast <>).

Typically, you need to choose what the foo function should return:

  • new instance of class A with specific data
  • access to an existing instance

If you need to make this decision at runtime (for example, according to your bool parameter), then pointers (simple or smart - independently) are the only option (also remember to delete the memory allocated manually).

0
source share

All Articles