C++ std::move() performance wise with lvalues - c++

I've just finished learning about lvalues, rvalues, move constructor and move operator.
I can see the added value of using move constructor with rvalues performance and usability wise.
But i can't see the added value of using move operator with move constructor with lvalues performance wise, sure there is a added value usability wise, but can't we achieve the same functionality for lvalues using some other technologies like pointers for example.
so my question is: what is the added value of using move operator with move constructor with lvalues performance wise.
Thanks for reading my question.
example:
class string{
public:
char* data;
string(){
data = nullptr;
}
string(const char* p)
{
size_t size = std::strlen(p) + 1;
data = new char[size];
std::memcpy(data, p, size);
}
~string()
{
delete[] data;
}
string(const string& that)
{
size_t size = std::strlen(that.data) + 1;
data = new char[size];
std::memcpy(data, that.data, size);
}
string(string&& that)
{
data = that.data;
that.data = nullptr;
}
string movee(string &that){
data = that.data;
that.data = nullptr;
}};
what is the difference performence wise:
string s1("test");
string s2(std::move(s1));
string s1("test");
string s2 = string();
s2.movee(s1);
In the case of rvalues, the compiler spares us the time and memory taken to reform a new object and assign the rvalue to it, and then using that new object to change the values in the moved-to object, thus increasing performance. But in the case of a lvalue object, the move operator is not increasing performance, it is increasing usability and readability of course, but it is not increasing the performance as if it was a rvalue, am I wrong?

You could achieve the same functionality using indirection with pointers. Indeed, we used to, and even now that is exactly what is happening inside your move constructors/assignment operators!
Yes, most of the benefit when you std::move a variable is in the cleanliness of the code. But this is not pointless. Stealing resources with move constructors/assignment operators allows us to do so neatly, and quickly, without hacks or any performance penalties. Your code will be more maintainable and easier to rationalise about. You will be much less tempted to add an extra layer of indirection, dynamically allocating things that didn't need to be dynamically allocated, just to get code that's in any way understandable, because now there won't be any benefit in doing so.
But! Don't forget that your standard containers are doing this for you behind the scenes, e.g. when std::vector resizes. That's very valuable. If we could only move from temporaries, that would not be possible and we'd have a massive wasted opportunity on our hands.
Doing it with temporaries isn't really any different; it's just that it's done for you without having to type std::move.

Related

Does the use of std::move have any performance benefits?

Please consider this code :
#include <iostream>
#include <vector>
#include <utility>
std::vector<int> vecTest;
int main()
{
int someRval = 3;
vecTest.push_back(someRval);
vecTest.push_back(std::move(someRval));
return 0;
}
So as far as I understand, someRval's value will be copied into vecTest on the first call of push_back(), but on the second someRval produces an x value. My question is, will there ever be any performance benefit, I mean probably not with int but would there maybe be some performance benefit when working with much larger objects?
The performance benefit from moving usually comes from dynamic allocation being ruled out.
Consider an over-simplified (and naive) string (missing a copy-assignment operator and a move-assignment operator):
class MyString
{
public:
MyString() : data(nullptr) {}
~MyString()
{
delete[] data;
}
MyString(const MyString& other) //copy constructor
{
data = new char[strlen(other.c_str()) + 1]; // another allocation
strcpy(data, other.c_str()); // copy over the old string buffer
}
void set(const char* str)
{
char* newString = new char[strlen(str) + 1];
strcpy(newString, str);
delete[] data;
data = newString;
}
const char* c_str() const
{
return data;
}
private:
char* data;
};
This is all fine and dandy but the copy constructor here is possibly expensive if your string becomes long. The copy constructor is however required to copy over everything because it's not allowed to touch the other object, it must do exactly what it's name says, copy contents. Now this is the price you have to pay if you need a copy of the string, but if you just want to use the string's state and don't care about what happens with it afterwards you might as well move it.
Moving it only requires to leave the other object in some valid state so we can use everything in other which is exactly what we want. Now, all we have to do instead of copying the content our data pointer is pointing to is just to re-assign our data pointer to the one of other, we're basically stealing the contents of other, we'll also be nice and set the original data pointer to nullptr:
MyString(MyString&& other)
{
data = other.data;
other.data = nullptr;
}
There, this is all we have to do. This is obviously way faster than copying the whole buffer over like the copy constructor is doing.
Example.
Moving "primitive" types like int or even char* does nothing different than copying them.
Complex types, like std::string, can use the information that you are willing to sacrifice the source-object state to make moving far more efficient than copying.
Yes, but it depends on the details of your application - size of the object, and frequence of the operation.
Casting it to an r-value and moving it (by using std:move()) avoids a copy. If the size of the object is large enough, this saves time (consider for example an array with 1 000 000 doubles - copying it typically means copying 4 or more MB of memory).
The other point is frequency - if your code does the respective operation very often, it can add up considerable.
Note that the source object is destroyed (made unusable) in the process, and this might or might not be acceptable for your logic - you need to understand it and code accordingly. If you still need the source object afterwards, it obvioulsy would not work.
Generally, don't optimize unless you need to optimize.

How to best handle copy-swap idiom with uninitialised memory

As an academic exercise I created a custom vector implementation I'd like to support copying of non-pod types.
I would like the container to support storing elements that do not provide a default constructor.
When I reserve memory for the vector, and then push_back an element (which manages it's own resources and has a copy and assignment operator implemented - I'm ignoring move constructors for the moment) I have an issue using the copy-swap idiom for that type.
Because the swap happens on a type that is still uninitialised memory, after the swap, the destructor which is called for the temporary will attempt to free some piece of uninitialised data which of course blows up.
There are a few possible solutions I can see. One is ensure all non-pod types implement a default constructor and call that (placement new) on each element in the collection. I'm not a fan of this idea as it seems both wasteful and cumbersome.
Another is to memset the memory for the space of the type in the container to 0 before doing the swap (that way the temporary will be null and calling the destructor will operate without error). This feels kind of hacky to me though and I'm not sure if there is a better alternative (see the code below for an example of this) You could also memset all the reserved space to 0 after calling reserve for a bunch of elements but again this could be wasteful.
Is there documentation on how this is implemented for std::vector as calling reserve will not call the constructor for allocated elements, whereas resize will (and for types not implementing a default constructor a constructed temporary can be passed as a second parameter to the call)
Below is some code you can run to demonstrate the problem, I've omitted the actual vector code but the principle remains the same.
#include <iostream>
#include <cstring>
// Dumb example type - not something to ever use
class CustomType {
public:
CustomType(const char* info) {
size_t len = strlen(info) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = info[i];
}
}
CustomType(const CustomType& customType) {
size_t len = strlen(customType.info_) + 1;
info_ = new char[len];
for (int i = 0; i < len; ++i) {
info_[i] = customType.info_[i];
}
}
CustomType& operator=(CustomType customType) {
swap(*this, customType);
return *this;
}
void swap(CustomType& lhs, CustomType& rhs) {
std::swap(lhs.info_, rhs.info_);
}
~CustomType() {
delete[] info_;
}
char* info_;
};
int main() {
CustomType customTypeToCopy("Test");
// Mimics one element in the array - uninitialised memory
char* mem = (char*)malloc(sizeof(CustomType));
// Cast to correct type (would be T for array element)
CustomType* customType = (CustomType*)mem;
// If memory is cleared, delete[] of null has no effect - all good
memset(mem, 0, sizeof(CustomType));
// If the above line is commented out, you get malloc error - pointer
// being freed, was not allocated
// Invokes assignment operator and copy/swap idiom
*customType = customTypeToCopy;
printf("%s\n", customType->info_);
printf("%s\n", customTypeToCopy.info_);
return 0;
}
Any information/advice would be greatly appreciated!
Solved!
Thank you to #Brian and #Nim for helping me understand the use case for when assignment (copy/swap) is valid.
To achieve what I wanted I simply needed to replace the line
*customType = customTypeToCopy;
with
new (customType) CustomType(customTypeToCopy);
Invoking the copy constructor not the assignment operator!
Thanks!
You don't use copy-and-swap for construction.
You use copy-and-swap for assignment in order to solve the following problem: the left side of the assignment is an already-initialized object, so it needs to free the resources it holds before having the right side's state copied or moved into it; but if the copy or move construction fails by throwing an exception, we want to keep the original state.
If you're doing construction rather than assignment---because the target is uninitialized---the problem solved by copy-and-swap doesn't exist. You just invoke the constructor with placement new. If it succeeds, great. If it fails by throwing an exception, the language guarantees that any subobjects already constructed are destroyed, and you just let the exception propagate upward; in the failure case the state of the target will be the same as it was before: uninitialized.

C++ Move assignment operator: Do I want to be using std::swap with POD types?

Since C++11, when using the move assignment operator, should I std::swap all my data, including POD types? I guess it doesn't make a difference for the example below, but I'd like to know what the generally accepted best practice is.
Example code:
class a
{
double* m_d;
unsigned int n;
public:
/// Another question: Should this be a const reference return?
const a& operator=(a&& other)
{
std::swap(m_d, other.m_d); /// correct
std::swap(n, other.n); /// correct ?
/// or
// n = other.n;
// other.n = 0;
}
}
You might like to consider a constructor of the form: - ie: there are always "meaningful" or defined values stores in n or m_d.
a() : m_d(nullptr), n(0)
{
}
I think this should be rewriten this way.
class a
{
public:
a& operator=(a&& other)
{
delete this->m_d; // avoid leaking
this->m_d = other.m_d;
other.m_d = nullptr;
this->n = other.n;
other.n = 0; // n may represents array size
return *this;
}
private:
double* m_d;
unsigned int n;
};
should I std::swap all my data
Not generally. Move semantics are there to make things faster, and swapping data that's stored directly in the objects will normally be slower than copying it, and possibly assigning some value to some of the moved-from data members.
For your specific scenario...
class a
{
double* m_d;
unsigned int n;
...it's not enough to consider just the data members to know what makes sense. For example, if you use your postulated combination of swap for non-POD members and assignment otherwise...
std::swap(m_d, other.m_d);
n = other.n;
other.n = 0;
...in the move constructor or assignment operator, then it might still leave your program state invalid if say the destructor skipped deleting m_d when n was 0, or if it checked n == 0 before overwriting m_d with a pointer to newly allocated memory, old memory may be leaked. You have to decide on the class invariants: the valid relationships of m_d and n, to make sure your move constructor and/or assignment operator leave the state valid for future operations. (Most often, the moved-from object's destructor may be the only thing left to run, but it's valid for a program to reuse the moved-from object - e.g. assigning it a new value and working on it in the next iteration of a loop....)
Separately, if your invariants allow a non-nullptr m_d while n == 0, then swapping m_ds is appealing as it gives the moved-from object ongoing control of any buffer the moved-to object may have had: that may save time allocating a buffer later; counter-balancing that pro, if the buffer's not needed later you've kept it allocated longer than necessary, and if it's not big enough you'll end up deleting and newing a larger buffer, but at least you're being lazy about it which tends to help performance (but profile if you have to care).
No, if efficiency is any concern, don't swap PODs. There is just no benefit compared to normal assignment, it just results in unnecessary copies. Also consider if setting the moved from POD to 0 is even required at all.
I wouldn't even swap the pointer. If this is an owning relationship, use unique_ptr and move from it, otherwise treat it just like a POD (copy it and set it to nullptr afterwards or whatever your program logic requires).
If you don't have to set your PODs to zero and you use smart pointers, you don't even have to implement your move operator at all.
Concerning the second part of your question:
As Mateusz already stated, the assignment operator should always return a normal (non-const) reference.

About time costs, what is more expensive: movement or overwritting? C++11

Let us suposse I have a stack of "unused" dynamic objects. Each time I need a new object, I use one of this "unused" objects as placeholder for the new petition. Something like:
template<typename T>
class my_list
{
public:
template<typename... Args>
T* newObject(Args&&... args)
{
if (unused.empty())
return new T(forward<Args>(args)...);
else {
auto* newbie = unused.top();
unused.pop();
newbie = new (newbie) T(forward<Args>(args)...); // l. X
return newbie;
}
}
private:
stack<T*> unused;
};
Question is, in line X, what is more efficient, the written sentence, or:
*newbie = std::move(T(forward<Args>(args)...));
That means, what is more time-efficient of both, a call of a new with newbie as address (avoiding petitions of new memory) or simply a movement of a new temporary object overwritting the original?
Here's another viable option. It has the advantage that while C++11 is still required for perfect forwarding, it works with library code that hasn't been updated to implement move construction and assignment.
T(forward<Args>(args)...).swap(*newbie);
Besides, your move assignment call already has a temporary object, no need to explicitly make it movable.
*newbie = T(forward<Args>(args)...);
Either of these will make it much easier to provide exception safety than the "first destroy, then construct in-place" approach.
The move is unnecessary, since a constructor call creates a prvalue temporary. Your question comes down to which is more efficient:
newbie->~T();
new (newbie) T(std::forward<Args>(args)...);
or
*newbie = T(std::forward<Args>(args)...);
Assuming T has a properly-written move assignment operator, there is likely to be little difference if any; in terms of side effects the destructor of T is called before the constructor in the first case, and after in the second, but there is no reason to believe that this would affect performance one way more than the other. The latter could result in more primitive value copies, but any decent optimising compiler will eliminate them.
In the absence of performance testing indicating that the former significantly improves performance, you should prefer the latter as it is far more readable, and easier to make exception safe.

Trying to write string class that can do move semantics from an std::string

I am writing my own string class for really just for learning and cementing some knowledge. I have everything working except I want to have a constructor that uses move semantics with an std::string.
Within my constructor I need to copy and null out the std::string data pointers and other things, it needs to be left in an empty but valid state, without deleting the data the string points to, how do I do this?
So far I have this
class String
{
private:
char* mpData;
unsigned int mLength;
public:
String( std::string&& str)
:mpData(nullptr), mLength(0)
{
// need to copy the memory pointer from std::string to this->mpData
// need to null out the std::string memory pointer
//str.clear(); // can't use clear because it deletes the memory
}
~String()
{
delete[] mpData;
mLength = 0;
}
There is no way to do this. The implementation of std::string is implementation-defined. Every implementation is different.
Further, there is no guarantee that the string will be contained in a dynamically allocated array. Some std::string implementations perform a small string optimization, where small strings are stored inside of the std::string object itself.
The below implementation accomplishes what was requested, but at some risk.
Notes about this approach:
It uses std::string to manage the allocated memory. In my view, layering the allocation like this is a good idea because it reduces the number of things that a single class is trying to accomplish (but due to the use of a pointer, this class still has potential bugs associated with compiler-generated copy operations).
I did away with the delete operation since that is now performed automatically by the allocation object.
It will invoke so-called undefined behavior if mpData is used to modify the underlying data. It is undefined, as indicated here, because the standard says it is undefined. I wonder, though, if there are real-world implementations for which const char * std::string::data() behaves differently than T * std::vector::data() -- through which such modifications would be perfectly legal. It may be possible that modifications via data() would not be reflected in subsequent accesses to allocation, but based on the discussion in this question, it seems very unlikely that such modifications would result in unpredictable behavior assuming that no further changes are made via the allocation object.
Is it truly optimized for move semantics? That may be implementation defined. It may also depend on the actual value of the incoming string. As I noted in my other answer, the move constructor provides a mechanism for optimization -- but it doesn't guarantee that an optimization will occur.
class String
{
private:
char* mpData;
unsigned int mLength;
std::string allocation;
public:
String( std::string&& str)
: mpData(const_cast<char*>(str.data())) // cast used to invoke UB
, mLength(str.length())
, allocation(std::move(str)) // this is where the magic happens
{}
};
I am interpreting the question as "can I make the move constructor result in correct behavior" and not "can I make the move constructor optimally fast".
If the question is strictly, "is there a portable way to steal the internal memory from std::string", then the answer is "no, because there is no 'transfer memory ownership' operation provided in the public API".
The following quote from this explanation of move semantics provides a good summary of "move constructors"...
C++0x introduces a new mechanism called "rvalue reference" which,
among other things, allows us to detect rvalue arguments via function
overloading. All we have to do is write a constructor with an rvalue
reference parameter. Inside that constructor we can do anything we
want with the source, as long as we leave it in some valid state.
Based on this description, it seems to me that you can implement the "move semantics" constructor (or "move constructor") without being obligated to actually steal the internal data buffers.
An example implementation:
String( std::string&& str)
:mpData(new char[str.length()]), mLength(str.length())
{
for ( int i=0; i<mLength; i++ ) mpData[i] = str[i];
}
As I understand it, the point of move semantics is that you can be more efficient if you want to. Since the incoming object is transient, its contents do not need to be preserved -- so it is legal to steal them, but it is not mandatory. Maybe, there is no point to implementing this if you aren't transferring ownership of some heap-based object, but it seems like it should be legal. Perhaps it is useful as a stepping stone -- you can steal as much as is useful, even if that isn't the entire contents.
By the way, there is a closely related question here in which the same kind of non-standard string is being built and includes a move constructor for std::string. The internals of the class are different however, and it is suggested that std::string may have built-in support for move semantics internally (std::string -> std::string).