copy vs std::move for ints
In this example, there is no difference. We will end up with 3 int
s with value 100. There could definitely be a difference with different types though. For instance, let's consider something like vector<int>
:
std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5
auto a_copy = a; // copy a. now we have two vectors of size 5
auto a_move = std::move(a); // *move* a into a_move
The last variable, a_move
, takes ownership of a
's internal pointers. So what we end up with is a_move
is a vector of size 5, but a
is now empty. The move
is much more efficient than a copy
(imagine if it was a vector of 1000 strings instead - a_copy
would involve allocating a 1000-string buffer and copying 1000 strings, but a_move
just assigns a couple pointers).
For some other types, one might be invalid:
std::unique_ptr<int> a{new int 42};
auto a_copy = a; // error
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing
For many types, there's no difference though:
std::array<int, 100> a;
auto a_copy = a; // copy 100 ints
auto a_move = std::move(a); // also copy 100 ints, no special move ctor
More generally:
T a;
auto a_copy = a; // calls T(const T& ), the copy constructor
auto a_move = std::move(a); // calls T(T&& ), the move constructor
What is the benefit of moving a range of elements in a vector vs. copying?
Here, I am moving a range of elements from
v1
tov2
, but is there any
particular advantage to doing this vs. copying?
No. Here is all happened just a range coping, because your usage of std::move
for primitive types just do coping. Therefore it does the same as simple if you would have:
std::vector<int> v2{v1.begin() + 2, v1.end()};
Therefore you are correct about the findings. However, it is called fundamental types/ primitive types, not PODs.
But in the former move of a range of elements, I don't see the usefulness.
Consider the case of std::vector</*expensive copy type*/>
, in which it makes sense to have a move of the underlying range elements, whenever is possible.
For instance consider the std::vector<std::string>
case
std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
std::vector<std::string> v2;
// reserve memory for unwanted reallocations
v2.reserve(std::distance(v1.begin() + 2, v1.end()));
// moves the string element in the range
std::move(v1.begin() + 2, v1.end(), back_inserter(v2));
// v1 now: 1 2
// v2 now: 3 4 5 6 7
(See a demo here)
As a side note, instead of std::move
the range in a separate line, for iterators, one could also use std::make_move_iterator
, to do the range move construction while declaration (if make sence).
#include <iterator> // std::make_move_iterator
std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
std::vector<std::string> v2{ std::make_move_iterator(v1.begin() + 2),
std::make_move_iterator(v1.end()) };
Cost of copy vs move std::shared_ptr
I wrote a benchmark. On my Macbook Air it is three times faster (g++
as well as clang++
-std=c++17 -O3 -DNDEBUG
). Let me know if you see problems with the benchmark.
#include <chrono>
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
using namespace std::chrono;
int COUNT = 50'000'000;
struct TimeIt
{
system_clock::time_point start;
TimeIt() {
start = system_clock::now();
}
~TimeIt() {
auto runtime = duration_cast<milliseconds>(system_clock::now()-start).count();
cout << runtime << " ms" << endl;
}
};
void benchmark_copy(const vector<shared_ptr<int>> &vec_src)
{
cout << "benchmark_copy" << endl;
vector<shared_ptr<int>> vec_dst;
vec_dst.reserve(COUNT);
TimeIt ti;
for(auto &sp : vec_src)
vec_dst.emplace_back(sp);
}
void benchmark_move(vector<shared_ptr<int>> &&vec_src)
{
cout << "benchmark_move" << endl;
vector<shared_ptr<int>> vec_dst;
vec_dst.reserve(COUNT);
TimeIt ti;
for(auto &sp : vec_src)
vec_dst.emplace_back(move(sp));
}
int main (int arg, char **argv){
vector<shared_ptr<int>> vec;
for (int i = 0; i < COUNT; ++i)
vec.emplace_back(new int);
benchmark_copy(vec);
benchmark_move(move(vec));
}
Copying vs Moving while casting objects
You don't need to write the copy and move constructors as the compiler will implicitly generate them if the only behavior is to copy/move the std::vector
member.
By the way, you may want to implement your ColumnVector
as a view of the Vector
(something like std::string_view
) so that there is even no move.
Why does std::move copy contents for a rvalue or const lvalue function argument?
Your vector is actually copied, not moved. The reason for this is, although declared as an rvalue reference, vec_
denotes an lvalue expression inside the function body. Thus the copy constructor of std::vector
is invoked, and not the move constructor. The reason for this is, that vec_
is now a named value, and rvalues cannot have names, so it collapses to an lvalue. The following code will fail to compile because of this reason:
void foo(int&& i)
{
int&& x = i;
}
In order to fix this issue, you have to make vec_
nameless again, by calling std::move(vec_)
.
why std::move behaves like std::copy?
For plain old data, moving and copying are identical. There's no way to move ordinary data other than by copying. Things are different if, for example, you have ownership of some other object that can be transferred without copying it (like std::string
or std::shared_ptr
has). But for int
, that doesn't apply.
Related Topics
Calling a Function Through Its Address in Memory in C/C++
How to Effectively Kill a Process in C++ (Win32)
C++ View Types: Pass by Const& or by Value
Qt - Remove All Widgets from Layout
C++11 Variable Number of Arguments, Same Specific Type
Performance Wise, How Fast Are Bitwise Operators VS. Normal Modulus
Show Two Digits After Decimal Point in C++
What Is a "Regular Type" in the Context of Move Semantics
_Attribute_((Weak)) and Static Libraries
Cc1Plus: Error: Unrecognized Command Line Option "-Std=C++11" with G++
Using Std::Move() When Returning a Value from a Function to Avoid to Copy
Std::Mutex Performance Compared to Win32 Critical_Section
Template Function Specialization for Integer Types
Are Global Variables in C++ Stored on the Stack, Heap or Neither of Them
How to Clone Object in C++? or Is There Another Solution