Example to use boost::weak_ptr to break cyclic dependencies - boost

I have seen one of the usages of boost::weak_ptr is to break cyclic dependencies. Can someone give me a simple concrete example to illustrate this feature?
Thank you

In simple terms:
{ // Enter scope
shared_ptr<A> my_a(new A);
shared_ptr<B> my_b(new B);
my_a->remember_this_b( my_b ); // Stores a copy of a smart pointer
my_b->remember_this_a( my_a ); // Stores a copy of a smart pointer
} // Leave scope. my_a and my_b are destroyed.
If both these functions stored a shared_ptr, the objects would never be deleted, because neither shared_ptr would reach a reference count of zero.
However, if either one used a weak_ptr, the object pointed to by the weak_ptr would be destroyed when leaving the scope. And that would in turn destroy the last shared_ptr to the other object.

Related

When does c++ right value destruct in this scenario?

Here is the code:
class SomeType {
public:
SomeType() {}
~SomeType() {}
std::string xxx;
}
bool funtion_ab() {
SomeType(); // This is a right val;
// The right val destructs here when I test the code. I want to make sure that it would always destructs here.
int a = 0, b = 10;
....// other code
return true;
}
Please tell me if you know the truth. Thank you!
What you have is called a temporary object. From §6.7.7,
Temporary objects are created
when a prvalue is converted to an xvalue
or, more specifically,
[Note 3: Temporary objects are materialized:
...
when a prvalue that has type other than cv void appears as a discarded-value expression ([expr.context]).
— end note]
and, on the lifetime, the same section has this to say
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
You can read more about the expression semantics, but in your case "full-expression" is fairly unambiguous.
SomeType();
The "full-expression" containing your constructor call is... the constructor call itself. So the destructor will be called immediately after evaluating the constructor. There are some exceptions to this rule (such as if the temporary object is thrown as an exception or is bound as a reference), but none of those apply here.
As noted in the comments, compilers are free to inline your constructor and destructor calls and then are free to notice that they do nothing and omit them entirely. Optimizers can do fun stuff with your code, provided it doesn't change the semantics. But a strict reading of the standard states that the destructor is called exactly where you suggested.

Accessing object T in vector<unique_ptr<T>> without taking ownership

I have the following member variable in a class:
std::vector<std::unique_ptr<Object>> objects_;
I explicitly want the vector to maintain ownership at all times. I've seen suggestions that in order for a member function to access a pointer in the vector and make changes to the object T wrapped in the std::unique_ptr, we must move the pointer to calling code, i.e:
void foo(int i) {
auto object = std::move( vector.at( i ) ); // move object to caller (caller owns)
object->dosomething();
vector.at(i) = std::move(object); // move back into vector (vector owns)
}
Another method was to work with raw pointers:
void foo(int i) {
Object* object = vector.at( i ).get();
object->doSomething();
}
However, I've been working with this:
void foo(int i) {
auto& object = vector.at( i );
object->doSomething();
}
Which is the correct and most robust method for my case? Does this function ever take ownership of the data in the std::unique_ptr? Is there a way to access Object without playing with the std::unique_ptr?
(excuse me if my methods are incorrect, I hope I got the point across)
The first approach will not retain ownership of the object if object->dosomething() throws an exception (i.e. it is not exception safe) since the second std::move() statement will not be executed.
Assuming C++11, both of the other approaches are effectively equivalent, subject to the assumption that the owned pointer is not null. Under the same assumption, the code can be simplified to
void foo(int i)
{
vector.at(i)->doSomething();
}
which will work with all C++ standards (not just C++11 or later).
It is possible to access the object without monkeying with the unique_ptr - simply store the pointer elsewhere and use that. However, that does compromise the purpose of using std::unique_ptr in the first place. And is error-prone - for example, the std::unique_ptr can destroy the object, and leave those other pointers dangling.
If you are really that worried about the potential of your vector losing ownership, consider using a shared_ptr instead.

Is there a way to make a moved object "invalid"?

I've some code that moves an object into another object. I won't need the original, moved object anymore in the upper level. Thus move is the right choice I think.
However, thinking about safety I wonder if there is a way to invalidate the moved object and thus preventing undefined behaviour if someone accesses it.
Here is a nice example:
// move example
#include <utility> // std::move
#include <vector> // std::vector
#include <string> // std::string
int main () {
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back (foo); // copies
myvector.push_back (std::move(bar)); // moves
return 0;
}
The description says:
The first call to myvector.push_back copies the value of foo into the
vector (foo keeps the value it had before the call). The second call
moves the value of bar into the vector. This transfers its content
into the vector (while bar loses its value, and now is in a valid but
unspecified state).
Is there a way to invalidate bar, such that access to it will cause a compiler error? Something like:
myvector.push_back (std::move(bar)); // moves
invalidate(bar); //something like bar.end() will then result in a compiler error
Edit: And if there is no such thing, why?
Accessing the moved object is not undefined behavior. The moved object is still a valid object, and the program may very well want to continue using said object. For example,
template< typename T >
void swap_by_move(T &a, T &b)
{
using std::move;
T c = move(b);
b = move(a);
a = move(c);
}
The bigger picture answer is because moving or not moving is a decision made at runtime, and giving a compile-time error is a decision made at compile time.
foo(bar); // foo might move or not
bar.baz(); // compile time error or not?
It's not going to work.. you can approximate in compile time analysis, but then it's going to be really difficult for developers to either not get an error or making anything useful in order to keep a valid program or the developer has to make annoying and fragile annotations on functions called to promise not to move the argument.
To put it a different way, you are asking about having a compile time error if you use an integer variable that contains the value 42. Or if you use a pointer that contains a null pointer value. You might be succcessful in implementing an approximate build-time code convention checker using clang the analysis API, however, working on the CFG of the C++ AST and erroring out if you can't prove that std::move has not been called till a given use of a variable.
Move semantics works like that so you get an object in any it's correct state. Correct state means that all fields have correct value, and all internal invariants are still good. That was done because after move you don't actually care about contents of moved object, but stuff like resource management, assignments and destructors should work OK.
All STL classes (and all classed with default move constructor/assignment) just swap it's content with new one, so both states are correct, and it's very easy to implement, fast, and convinient enough.
You can define your class that has isValid field that's generally true and on move (i. e. in move constructor / move assignment) sets that to false. Then your object will have correct state I am invalid. Just don't forget to check it where needed (destructor, assignment etc).
That isValid field can be either one pointer having null value. The point is: you know, that object is in predictable state after move, not just random bytes in memory.
Edit: example of String:
class String {
public:
string data;
private:
bool m_isValid;
public:
String(string const& b): data(b.data), isValid(true) {}
String(String &&b): data(move(b.data)) {
b.m_isValid = false;
}
String const& operator =(String &&b) {
data = move(b.data);
b.m_isValid = false;
return &this;
}
bool isValid() {
return m_isValid;
}
}

function that modifies object pointed to by std::unique_ptr<T>

Somewhere in my code I have a local std::unique_ptr<T>. I need to do stuff with the object pointed at, and I use a function for that:
std::unique_ptr<T> some_function( std::unique_ptr<T> &t )
{
// do stuff
return t;
}
I call the function like this:
std::unique_ptr<T> some_T_ptr( new T(/*args*/) );
vector_of_finalized_Ts.push_back( std::move(some_function(std::move(some_T_ptr))));
Now I wonder, is there a better way to get the necessary functionality? It just seems two moves are pretty superfluous and potentially dangerous. I do have error handling code I'm not showing here, but that's beside the point.
It is all about ownership. Do you want some_function to take ownership of the pointer or not? If not, you can just pass a raw pointer to some_function. If you want some_function to take ownership (and return ownership), then it should take the unique_ptr by value. Otherwise the return statement (which should be std::move(t)) will be moving from a reference of unknown origins.
std::unique_ptr<T> some_function( std::unique_ptr<T> t )
{
// I own t here and will delete it if an exception happens
// do stuff
// I'm transferring ownership back to the caller
// (who may or may not accept ownership)
return std::move(t);
}
vector_of_finalized_Ts.push_back( some_function(std::move(some_T_ptr)));
or:
void some_function( T* t )
{
// I don't own t and won't delete it if an exception happens
// do stuff
}
some_function(some_T_ptr.get());
vector_of_finalized_Ts.push_back( std::move(some_T_ptr));
Either design is fine. It just depends on what code should own the pointer (especially if an exception is thrown at some point).
(Ignoring the unrelated syntax error in your code. See my comment above for that.)
As far as your snippet goes, your code is valid. The verbosity of the moves is the price you pay for using std::unique_ptr in this manner, and for passing the unique_ptr into the function rather than a reference to the object itself.
I suppose you have your good reasons for wanting some_function to take a std::unique_ptr and, if that's the case, then as far as I can tell you can't really do any better.
If you don't have your good reasons then, well, there's your answer. :)
Hope that helps.
Your problem is that you both take the unique_ptr by reference and return it. It's a unique pointer- you're treating it liked a shared pointer, and you're left with a wasted nullptr value on the stack. If you took it by value or by rvalue reference, you could just call some_function directly, and you don't have to move the result.
std::unique_ptr<T> some_function( std::unique_ptr<T> &&t )
{
// do stuff
return t;
}
vector_of_finalized_Ts.push_back( some_function(std::unique_ptr<T>(new T(...))));

pushing back an boost::ptr_vector<...>::iterator in another boost::ptr_vector?

I have the following code (just typed it in here, might have typos or stuff):
typedef boost::ptr_vector<SomeClass> tvec;
tvec v;
// ... fill v ...
tvec vsnap;
for(tvec::iterator it = v.begin(); it != v.end(); ++it)
{
if((*v).anyCondition)
vsnap.push_back( it ); // (*it) or &(*it) doesn't work
}
My problem is now that i cant push_back an iterator in any way, I just don't get the pointer out of the iterator.
Is there an easy way i didnt see, or are boosts ptr_vector the false choice for this case?
Thanks in advance.
Dereferencing a ptr_vector::iterator gives you a reference. Then you can use & to get the address of that reference, so vsnap.push_back(&(*it)) should compile. What error are you getting?
Besides, note that your usage is incorrect. The old ptr_vector owns the object, no matter what you do with the object's address. So with your code you'd have two ptr_vectors owning the same object. Then they would both try to delete it, and you'd crash. You probably want to transfer ownership instead:
vsnap.push_back(v.release(it));
Of course, this removes the object from the old vector before adding it to the new one. If you want the object to stay in both vectors, you can use std::vector or std::vector >. Another alternative is to keep the first one a boost::ptr_vector but make the second one a std::vector that owns nothing and just points to objects in the original vector. Then you would have to be careful with lifetimes.
You need to clone the objects held by the first vector:
for(tvec::iterator it = v.begin(); it != v.end(); ++it)
{
if((*v).anyCondition)
vsnap.push_back(new_clone(*it));
}

Resources