Overloading for pass-by-value and pass-by-rvalue-reference - c++11

I have two overloads of a subroutine that takes an argument of a type that occupies several Megabytes of dynamic memory and has a move constructor and assignment operator:
// Version intended for use when we the caller has
// deliberately passed an rvalue reference using std::move
void MyClass::setParameter(MyMoveableType &&newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
// Version intended for use when the caller has passed
// some other type of value which shouldn't be moved
void MyClass::setParameter(MyMoveableType newParameter)
{
m_theLocalParameter = std::move(newParameter);
}
The intention is clearly that the first overload moves the contents of newParameter from wherever up the chain of subroutine-calls the newParameter object originated, whilst the second overload creates a brand new copy of newParameter (or invokes copy elision to avoid doing so where appropriate, such as where the argument is actually the return value from a function) and then moves the copy into the local data member, thus avoiding a further copy.
However, if I try actually to move an object into my class using the first overload:
{
MyClass theDestination;
MyMoveableType theObject
...
// ...Various actions which populate theObject...
...
TheDestination.setParameter(std::move(theObject));
...
}
...then on every compiler I've tried I get an error along the lines of:
call to member function 'setParameter' is ambiguous
Now I can see that passing an rvalue reference to the second overload would in fact be perfectly legal, and is what I'd expect the compiler to do, without giving a warning, if I hadn't provided the first overload. Even so, I'd expect it to be perfectly clear to the compiler what the intent of this code is, and therefore I'd expect that it would select the second overload as being the best match.
I can eliminate the error by redefining the second constructor to take a const reference and do away with the std::move (though it wouldn't be an error to
leave it in; the compiler would just ignore it). This would work all right, but I'd lose the opportunity to take advantage of copy elision. This could be
significant in performance terms for this particular application; the objects under discussion are high-resolution video frames streaming through at 30
frames per second.
Is there anything I can do under this circumstance to disambiguate the overloads and so have both a pass-by-value and pass-by-rvalue-reference version of my routine?

The intention is clearly that the first overload moves the contents of newParameter from wherever up the chain of subroutine-calls the newParameter object originated, whilst the second overload creates a brand new copy
Which is not really how you do it. You have two sane options:
Approach A
You write just the value overload and then move from it anyway - that means you'll always pay a constructor price, either move or copy.
Approach B
You write overloads for (const T&) and (T&&). That way you copy in the first one and skip the move CTOR in the second one using perfect forwarding.
I recommend approach A as a default, and B only when the c-tor call actually matters that much.

Related

move semantics with temps allocated with new

I'm just wondering if move semantics are restricted to syntax style B.
More specifically, with style B the object is created on the stack and moved. With style A, the object is created on the heap, but it seems can't be moved.
The question very specifically is, can you use move semantics such that the temp is created with NEW? If so, how?
//move c'tor
A(A&& other) : num(other.num), s(other.s){
other.num = 0;
other.s = nullptr; //dyn alloc obj
}
If you do this, it doesn't work (syntax style A).
A a2(new A("blah")); //error
A a2(move(new A("blah"))); //error
This is ok (syntax style B)
A a2(A("blah")); //uses c'tor once
A a2(move(A("blah"))) //uses c'tor followed by move c'tor
You seem to be confused about a number of things, so I'll try to shed some light. You probably know most of this already.
Move semantics were designed to allow objects to transfer ownership of their data to another object. This was motivated largely to avoid copying from temporary objects that didn't need it.
The move constructor is much like the copy constructor, A(const A&), but only accepts a non-const xvalue of the same type, A(A&&) (think of it as an expiring value). Therefore, this constructor can be invoked when given something like a return value from a function or a variable moved via std::move.
Now, the function std::move in itself is a bit of a misnomer, it doesn't actually do anything. All it does it cast a T or T& into a T&&.
To address your question directly, nothing I've mentioned is specific to where the moving object is located, but it is specific about the types. A("blah") calls the constructor with automatic memory and returns that A. new A("blah") on the other-hand calls the constructor with dynamic memory and returns a pointer to that A, ergo an A*. So your syntax A is not trying to invoke the move constructor, but another constructor like A(A*).
To move from an object referenced by a pointer, all you need to do is derefence and move:
A* a1 = new A("blah");
A a2(std::move(*a1));
There's nothing stopping you from defining a constructor like A(A*), but that shouldn't be needed and isn't recommended for using move semantics.
Also, your syntax B comments are incorrect; both are a value-constructor A("blah") followed by the move-constructor A(A&&); the std::move doesn't add anything here.

What's the purpose of writing void method and is usefulness in main method

when it doesn't return any value, what are it essence?. And most method with void I have seen have println in is block of statements. what println display is it not a value? what determine is usage(void type method)?
Note: I am novice to programming. And all answers I have seen on void type method are about , doesn't return value.
If a function returns void, it means any action the function does is through "side-effects".
Side effects are when a function directly changes the state of something external to the function itself.
When you have a function that prints to the screen using println, it's modifying the global output stream (which is outside of the function) by inserting into it whatever text you gave it.
Keep in mind though functions can have side effects and return a value at the same time. A pop operation usually modifies the stack object by removing an element from it (side effects), then returns whatever object it popped.
Side effects aren't necessary in most cases, but they can be useful. In the above pop example, if the method didn't modify the stack directly, it would need to return both a new stack with an element removed, and the removed element. Two things are returned at once usually by wrapping them in something like a tuple.
If your code returns everything and relies on side effects as little as possible, it's known as functional code. If you have code that relies on side effects, it's known as imperative code (gross simplification, but it gets the idea accross).

C++ - Clear array of pointers stored in two places

In a constructor for a class Block i push the created instance into a static vector static std::vector<Block*> allBlocks, and remove them in the destructor.
This works if i just create blocks without pointers, ie. Block b;
However, want to have another class return a std::vector<Block*> grid for use, which creates them and adds them into the allBlocks vector also. Destroying the grid vector doesn't seem to run their destructors.
I've tried:
grid.clear() using erase/remove and just pop_back
What would be a better way to store/return them so that when the grid is destroyed, so will the contained Blocks.
Okay, so if you want a really better way, a couple of changes:
No statics! They aren't necessary at all here.
If, as you've stated, you want two containers containing those objects but in such a way that removing one object removes them from every other container, it becomes more problematic.
First, it's impossible for one container to remove elements from another unless it has a reference to it in a way. You could create a variable that would hold all of the containers of your blocks and use that to remove the block from every container, but... yeah.
In this case, a weak reference solution is acceptable, as long as you remember about the implications.
std::shared_ptr ownership and std::weak_ptr reference
Create an std::set<shared_ptr<Block>> blocks;, then two containers with weak references; might be called allBlocks or grid or whatever. Those weak references collection could be for example std::set<std::weak_ptr<Block>>.
Now when removing an element from the grid or allBlocks, you need to remove it from the blocks. To do the lookup on it, you'd need something like this:
struct null_deleter {
void operator()(void const *) const { }
};
To properly create a value for the set lookup. Then, when iterating over any other container, you'd need to use ptr.expired() on the weak_ptr reference in order to see if it was deleted previously.
The caveat of that idea is that the original shared_ptr isn't shared; the class is used just for convenience of weak_ptr and automatic destruction.
std::unique_ptr ownership and int reference
Another, perhaps simpler way is to use std::unordered_map and create a "unique ID" key for each block.
std::unordered_map<unsigned, std::unique_ptr<Block>> blocks;
Now your containers need to be std::set<unsigned>, and the lookup would look like:
for (auto b : grid) {
auto bIt = blocks.find(b);
if (bIt != blocks.end) {
// do things with *bIt
} else {
// e.g. add the b to the "delete list"
}
}
Now you could process your "delete list" and remove the dead ids from the container.
Wrapping up
Since this might get tedious to use, a nice idea could be to wrap the set into a container that would do the cleanup before returning begin() or end() for custom iteration across Block values.
Similarly, the destructor of such wrapped structure could remove the values from the map, thus effectively making all ids in all other containers dangling.
This of course raises an issue of thread safety, because the original blocks map would need to be locked for the whole iteration; at least for modification. Having cbegin()/cend() could allow two threads to read from the same shared map, but ... The kind of problems that arise when sharing data across threads are out of scope for this post, though.
Poisoning
Another idea that came to my mind is sometimes referred to as "poisoning". In this case, you don't need a master container; both of your regular containers would hold shared_ptrs to the Blocks... with a twist.
When a Block is chosen for deletion, a special flag is set on it. It becomes "poisoned", and every container should sweep such blocks before doing iteration.
If every container indeed does so, all references to the Block die and its destructor will fire properly. You're essentially communicating the command through a special value of it.
If you don't want to modify the Block class, having std::shared_ptr<std::optional<Block>> and nullyfying the optional can work just the same, except the destructor of the Block will run immediately, and not when the last structure decides to do its sweep. This might be better or worse depending on your goals and needs.

Object state after move semantics

I want to understand move semantics and rvalue reference and the object state after the function call.
For example: I expect that caller fills the list and gets to the constructor argument:
typedef std::list<int> IntList;
class IntHolder {
public:
explicit IntHolder(IntList&& l)
: m_h(l)
{}
private:
IntList m_h;
};
IntList a;
a.push_back(1);
IntHolder holder(a);
// ... is 'a' guaranteed empty (not empty) here?
a is guaranteed to not be empty, because it was never passed as an rvalue reference: it is a declared variable, not a compiler generated temporary, and hence cannot be passed as an rvalue reference.
What's happening here is that a temporary IntList gets copy-constructed from a, and that temporary is passed to your constructor. a itself remains intact.
To make things really complicated: even that temporary is not moved! When you use an rvalue reference, it decays to a normal reference, which happens when you say m_h(l) in your initializer list. If it were otherwise, you would not be able to access l from within your constructor. So, the temporary is copied a second time. You can enforce move semantics by replacing m_h(l) with m_h(std::move(l)).
Whenever you try to invoke move semantics, what happens depends on how the class you are using is written. Thus, there are no language guarantees. The only thing a move constructor needs to make sure is that the destructor will not mess up when it is run. It is simply an error to access an object in any way after invoking move semantics on it.

State of object after std::move construction

Is it legal/proper c++0x to leave an object moved for the purpose of move-construction in a state that can only be destroyed? For instance:
class move_constructible {...};
int main()
{
move_constructible x;
move_constructible y(std::move(x));
// From now on, x can only be destroyed. Any other method will result
// in a fatal error.
}
For the record, I'm trying to wrap in a c++ class a c struct with a pointer member which is always supposed to be pointing to some allocated memory area. All the c library API relies on this assumption. But this requirement prevents to write a truly cheap move constructor, since in order for x to remain a valid object after the move it will need its own allocated memory area. I've written the destructor in such a way that it will first check for NULL pointer before calling the corresponding cleanup function from the c API, so that at least the struct can be safely destroyed after the move.
Yes, the language allows this. In fact it was one of the purposes of move semantics. It is however your responsibility to ensure that no other methods get called and/or provide proper diagnostics. Note, usually you can also use at least the assignment operator to "revive" your variable, such as in the classical example of swapping two values.
See also this question

Resources