Passing const reference or shared pointer / vector and assign to non-reference member - c++11

CPP check is complaining about this construction:
void setThing(std::shared_ptr<Thing> theThing)
{
memberThing = theThing;
}
where memberThing is a std::shared_ptr<Thing>.
When changing to:
void setThing(const std::shared_ptr<Thing>& theThing);
cppcheck is not complaining anymore.
I need a shared pointer, I can't guarantee theThing will exist forever, so I don't want to have a member reference. But why is a const reference working when assigning it to a not-reference member? And what happens actually? Is the shared pointer copied to memberThing? Where did the reference go?
And actually exactly the same question for
void setThings(std::vector<std::shared_ptr<Thing>> theThings)
{
memberThings = theThings;
}
where memberThing is a std::vector<std::shared_ptr<Thing>>.
When using this construction, what is happening with the vector? Is it copied? What happens when the original vector is destroyed? Can I better use the first version or the second?
I am quite confused a const vector& can be assigned to a vector (not-reference). Is that a good idea anyway? What is the best thing to do in this situation? And why?

Related

Are constant references still best practice in c++11 and later?

I recently read an article about the new move semantics in C++. It was about the confusion how to best implement a return value for a large object. The conclusion was, just implement it like return by copy and let the compiler decide if a move works best.
Now I wondered if this is true for function parameters as well meanwhile.
Currently I use const references like this:
void setLargeObject(const LargeObject &obj) {
_obj = obj;
}
Instead of the simple copy:
void setLargeObject(LargeObject obj) {
_obj = obj;
}
Are parameters, to copy large objects, passed by const reference still be the best practice in C++11 and later?
If setting the property requires taking ownership of the value, then pass by value. It will be copied if necessary before the function call, when the parameter is initialized. Inside the function, move it into place.
void setLargeObject(LargeObject obj) {
_obj = std::move(obj);
}
If LargeObject doesn't support move semantics (so having std::move changes nothing), then you might use const& to limit the performance hit to one copy instead of two. However, the best solution is to add movability, not to stay with const&.

Casting std::shared_ptr<T> to void*

A library requires binary data to be shared as void *.
The data to be shared is available as shared_ptr<T>.
Is there a way to cast shared_ptr<T> to void * ?
PS: Static casting does not work:
error: invalid static_cast from type ‘std::shared_ptr<DataPacket>’ to type ‘void*’
static_cast<void *>(binData);
You're going about this wrong. Your problem is not "I need to interpret a shared_ptr<T> as a void*" — your problem is "I have a smart pointer to an object, and I need a dumb pointer to that object".
shared_ptr<T> has a function that does exactly that.
shared_ptr<T> smart;
// ... some code here points smart at an object ...
T *dumb1 = smart.get(); // creates a dumb pointer to the object managed by smart
void *dumb2 = smart.get(); // dumb pointers automatically convert to void*
Do be careful to note that the dumb pointer this creates does not participate in the shared ownership scheme, so you have to take care to ensure the lifetime of the object lasts as long as you need it to.

C++ std::sort of const struct

I have the following struct in a vector
struct ub_node {
const size_t index;
const double ub_dist;
bool operator<(const ub_node &rhs) const { return ub_dist< rhs.ub_dist; }
};
I would like to sort that vector. I have tried using std::sort but I get a compile error:
error: use of deleted function ‘ub_node& ub_node::operator=(ub_node&&)’ with a reference to the line where I do std::sort(result.begin(), result.end());, where result is of type vector<ub_node>.
As far as I understand, the const does NOT affect the execution time, but merely ensures that the programmer (me) does not do anything stupid. If this is the case, I might remove the const and try to ensure that I do not change the node afterwards. Can someone confirm this? Or help me to sort it?
As far as I understand, the const does NOT affect the execution time, but merely ensures that the programmer (me) does not do anything stupid.
Correct.
Sorting a vector swaps the elements around, which is not possible if the elements have immutable data (with your ub_node type you can't even remove or insert an element anywhere except the end of the vector, because that also needs to modify existing elements).
I suggest you remove the const from your members, so the type is possible to modify, and then structure your code so that parts of the program which shouldn't modify it only interacts with the class through const ub_node& or const ub_node*.
That means that the class is modifiable when necessary, but won't be modified by parts of the program that aren't supposed to modify it.

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;
}
}

Resources