When I run the code below it produces the following output,
The first part used the template directly,
the second using a class that is derived from the template.
The moving semantics is not invoked in the derived class (shown in bold)
Template Dummy: initializing constructor
Template Dummy: initializing constructor
Template Dummy: empty constructor
Template Dummy: empty constructor
Template Dummy: + operator
Template Dummy: move assignment
2
Template Dummy: initializing constructor
Template Dummy: initializing constructor
Template Dummy: empty constructor
Template Dummy: empty constructor
Template Dummy: + operator
Template Dummy: copy constructor
Template Dummy: copy assignment
2
The reason, I think, is clear - naming an argument turns the argument into an lvalue, thus the template receives an lvalue and invokes a copy constructor.
The question is how to force move semantics in this case?
#include <iostream>
using namespace std;
template <typename T> class Dummy {
public:
T val;
Dummy& operator=(const Dummy& d){
val = d.val;
cout << "Template Dummy: copy assignment\n" ;
return *this;
}
Dummy operator+(const Dummy &d) {
Dummy res;
res.val = val + d.val;
cout << "Template Dummy: + operator\n" ;
return res;
}
// constructors
Dummy() {
val = 0;
cout << "Template Dummy: empty constructor\n" ;
}
Dummy(const T v) {
val = v;
cout << "Template Dummy: initializing constructor\n" ;
}
Dummy(const Dummy &d) {
val = d.val;
cout << "Template Dummy: copy constructor\n" ;
}
// move semantics
Dummy(const Dummy&& d) {
val = d.val;
cout << "Template Dummy: move constructor\n" ;
}
Dummy& operator=(const Dummy&& d){
val = d.val;
cout << "Template Dummy: move assignment\n" ;
return *this;
}
};
class FloatDummy : public Dummy<float> {
public:
FloatDummy& operator=(const FloatDummy& d){
Dummy<float>::operator=(d);
return *this;
}
FloatDummy operator+(const FloatDummy &d) {
return (FloatDummy) Dummy<float>::operator+(d);
}
// constructors
FloatDummy() : Dummy<float>() {};
FloatDummy(float v) : Dummy<float>(v) {}
FloatDummy(const FloatDummy &d) : Dummy<float>(d) {}
FloatDummy(const Dummy<float> &d) : Dummy<float>(d) {}
// move semantics
FloatDummy(const FloatDummy&& d) : Dummy<float>(d) {}
FloatDummy& operator=(const FloatDummy&& d){
// here d is already an lvalue because it was named
// thus the template invokes a copy assignment
Dummy<float>::operator=(d);
return *this;
}
};
int main() {
Dummy<float> a(1), b(1);
Dummy<float> c;
c = a + b;
cout << c.val << '\n';;
FloatDummy d(1), e(1);
FloatDummy f;
f = d + e;
cout << f.val << '\n';
}
You cannot move from a const&. To fix, simply remove const from all your move operations:
FloatDummy(FloatDummy&& d) : Dummy<float>(d) {}
// ^^^^^^^^^^^^ no longer FloatDummy const&&
FloatDummy& operator=(FloatDummy&& d) { /*...*/ }
// ^^^^^^^^^^^^ ditto
The essence of moving is taking ownership of resources, how can you take ownership of something if you can't modify your source? Therefore, move operations do not work with const types by default.
You'll want to do the same for the Dummy class.
You need to call std::move() to cast d to an rvalue reference: Even though d's parameter type is rvalue reference, inside the function itself d is pretty much considered an lvalue reference. This means that you still need to cast it to rvalue reference (the whole point of std::move()) when you pass it to whatever is actually consuming it.
In your case, it's right when you pass it to Dummy<float>'s constructor or Dummy<float>::operator=:
FloatDummy(FloatDummy&& d) : Dummy<float>(std::move(d)) {}
// ^^^^^^^^^ calling std::move()
// otherwise copy ctor overload is chosen
FloatDummy& operator=(FloatDummy&& d)
{
Dummy<float>::operator=(std::move(d));
// ^^^^^^^^^ ditto
return *this;
}
Related
I am writing a template function which accepts a custom class (that can be any class or primitive type) as a template argument, then reads some data (of that type) from an input stream, and then stores it an unordered map similar to this one:
std::unordered_map<CustomClass, std::vector<CustomClass>> map;
I have implemented a custom class to test the behavior. I have overloaded the std::hash so that this class can be stored in an unordered map as a key and overloaded all operators and constructors such that whenever they are called, I get a message in the console (example, when a copy constructor is called, I get a message "copy constructor [..data...]")
EDIT: As requested in the comments, here is the custom class definition and implementation (please note: the class here is only a placeholder so we can discuss the general idea behind this question. I am well aware that it is dumb and should not be implemented like this. The code for operators >> and << is not here, to avoid clutter)
class CustomClass {
public:
CustomClass(int a=0) {
std::cout << "default constructor" << std::endl;
m_data = a;
}
CustomClass(const CustomClass& other) {
std::cout << "copy constructor " ;//<< std::endl;
m_data = other.m_data;
std::cout << "[" << m_data << "]" << std::endl;
}
CustomClass(CustomClass&& other) {
std::cout << "move cosntructor" << std::endl;
m_data = other.m_data;
}
CustomClass& operator=(const CustomClass& other) {
std::cout << "copy assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
CustomClass& operator=(CustomClass&& other) {
std::cout << "move assignment operator" << std::endl;
if(this != &other){
m_data = other.m_data;
}
return *this;
}
~CustomClass() {
std::cout << "destructor" << std::endl;
}
int m_data;
};
Now my question is this: Is it possible to read data from the input stream and construct it inplace where it is needed without a copy constructor call?
Example of some code:
CustomClass x1; // default constructor call
CustomClass x2; // default constructor call
std::cout << "----" << std::endl;
std::cin >> x1 >> x2; // my input
std::cout << "----" << std::endl;
map[x1].emplace_back(x2); // 2 copy constructor calls
std::cout << "----" << std::endl;
std::cout << map[x1][0] << std::endl; // operator== call
std::cout << "----" << std::endl;
And here is an example output from that code:
default constructor
default constructor
----
[1]
[2]
----
copy constructor [1]
copy constructor [2]
----
operator ==
[2]
----
destructor
destructor
destructor
destructor
I would like to have it so that every object of this class is constructed only once.
Is it possible to avoid these copy constructors? If not both, then at least the one that is called during the emplace_back() call? Is it possible to construct the object in the vector exactly where it needs to be in memory but that this sort of call works for every type?
If I need to further elaborate on my question please tell me in the comments, I will be happy to do so
So you have an std::vector and you want to put an element there avoiding unnecessary copying. Assuming that move constructor for your class is cheap, the first option is to define a non-trivial constructor, read the parameters from stream and then emplace_back a newly created object:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.emplace_back(size, value);
Here I defined the CustomClass as a vector of integers, and it has a constructor that takes 2 parameters: size and the value. For sure it is cheaper to read there two integers and create the instance of CustomClass only once and using the emplace_back for this purpose, rather than to create the instance and copy it using push_back:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
CustomClass instance(size, value);
v.push_back(instance);
This however doesn't give you much benefits to compare with pushing back the r-value:
using CustomClass = std::vector<int>;
std::vector<CustomClass> v;
size_t size;
int value;
std::cin >> size >> value;
v.push_back(CustomClass(size, value));
Anyway, you need to keep in mind that both push_back and emplace_back may require reallocation of the elements, and that may be inefficient, especially if your CustomClass has no no-throwing move constructor.
Another problem could be if your class doesn't have a reasonable constructor (or the size of the values you need to pass to the constructor are almost the size of the object). In this case I'm offering you the solution to resize() and read to the back()
If the reallocation is something that you are not afraid of (for example you know the number of elements ahead of time and reserve the buffer), you can do the following:
std::vector<CustomClass> v;
v.resize(v.size() + 1);
std::cin >> v.back();
In this case you create a default value once and then read the contents.
Another solution could be to pass the std::istream to the constructor of CustomClass:
class CustomClass {
public:
CustomClass(std::istream&);
};
std::vector<CustomClass> v;
v.emplace_back(cin);
Update:
Assuming that you know nothing about the actual type of the CustomClass, the most generic (not fully generic, as it still requires default constructor to be able to be pushed with resize()) is to use resize()/back() idiom.
This is how you do it (avoids any unnecessary ctor calls, including a default one):
#include <vector>
#include <unordered_map>
#include <cstdio>
#include <iostream>
using namespace std;
//--------------------------------------------------------------------------
template <class F> struct inplacer
{
F f;
operator invoke_result_t<F&>() { return f(); }
};
template <class F> inplacer(F) -> inplacer<F>;
//--------------------------------------------------------------------------
struct S
{
S(istream&) { printf("istream ctor\n" ); }
S() { printf("ctor\n" ); }
~S() { printf("dtor\n" ); }
S(S const&) { printf("cctor\n"); }
S(S&&) { printf("mctor\n"); }
S& operator=(S const&) { printf("cop=\n"); return *this; }
S& operator=(S&&) { printf("mop=\n"); return *this; }
friend bool operator==(S const& l, S const& r) { return &l == &r; } //!! naturally, this needs proper implementation
};
template<> struct std::hash<S>
{
size_t operator()(S const&) const noexcept { return 0; } //!! naturally, this needs proper implementation
};
//--------------------------------------------------------------------------
template<class R> struct read_impl; // "enables" partial specialization
template<class R> R read(istream& is)
{
return read_impl<R>::call(is);
}
template<> struct read_impl<S>
{
static auto call(istream& is) { return S(is); }
};
template<class T> struct read_impl<vector<T>>
{
static auto call(istream& is)
{
vector<T> r; r.reserve(2); //!! naturally you'd read smth like length from 'is'
for(int i = 0; i < 2; ++i)
r.emplace_back(inplacer{[&]{ return read<T>(is); }});
return r;
}
};
template<class K, class V> struct read_impl<unordered_map<K, V>>
{
static auto call(istream& is)
{
unordered_map<K, V> r;
r.emplace( inplacer{[&]{ return read<K>(is); }}, inplacer{[&]{ return read<V>(is); }} );
return r;
}
};
//--------------------------------------------------------------------------
auto m = read<unordered_map<S, vector<S>>>(cin);
As you can see in the output -- you end up with 3 "istream ctor" calls and 3 "dtor" calls.
As for iostreams -- stay away from them if you care about performance, clarity, etc... The most ridiculous library ever.
P.S. "Partial specialization for function templates" trick is stolen from here.
I have the following code and its output printed below. I can't seem to understand why one set of braced initialization results in the move constructor being called, while the other results in the copy constructor. I have somewhat narrowed it down to direct-list-initialization vs copy-list-initialization per https://en.cppreference.com/w/cpp/language/list_initialization
I just can't quite figure out which case my code belongs to. Thanks in advance.
#include <cstdint>
#include <iostream>
using namespace std;
struct Foo {
Foo() {
cout << "create foo\n";
}
~Foo() {
cout << "delete foo\n";
}
Foo(const Foo& f) {
cout << "copy foo\n";
}
Foo(Foo&& f) noexcept {
cout << "move foo\n";
}
Foo& operator=(const Foo& f) = delete;
Foo& operator=(Foo&& f) = delete;
};
int32_t main() {
pair<uint32_t, Foo> f1{0, Foo{}}; // Calls move ctor
cout << "------------------------\n";
pair<uint32_t, Foo> f2{0, {}}; // Calls copy ctor
cout << "------------------------\n";
return 0;
}
This results in
create foo
move foo
delete foo
------------------------
create foo
copy foo
delete foo
------------------------
delete foo
delete foo
Let's take a look at two of the two-argument constructors of pair: [pairs.pair]
EXPLICIT constexpr pair(const T1& x, const T2& y);
template<class U1, class U2> EXPLICIT constexpr pair(U1&& x, U2&& y);
The second constructor uses perfect forwarding, and U2 cannot be deduced from {}. Therefore, the first version is selected when {} is used. When Foo{} is used instead, the argument has type Foo, so U2 is deduced to be Foo, causing the forwarding version to be selected.
Following the code-snippet below, I attempt to pass a Boo<int> instance through the Boo<T>::Boo(Foo const &) constructor overload, which I cannot manage to do.
#include <iostream>
struct Foo { };
template <typename T>
struct Boo : public Foo
{
// Boo(Boo<T> const &) = delete; // Leaves (2) without a constructor
Boo() { std::cout << "Beep " << sizeof(T) << std::endl; }
Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};
void fun(Foo const &) { }
int main()
{
Boo<int> x; // (1) Output: Beep 4
Boo<int> y(x); // (2) Output:
Boo<double> z(x); // (3) Output: Boop 8
fun(x); // (4) Compiles
return 0;
}
In the code-snippet I tried to write a simplistic scenario which can be copy-pasted to play around with, if need be.
At (1), we generate a Boo<int> instance x, which uses the Boo<T>::Boo() constructor overload.
At (2), we pass instance x to the constructor of instance y, which uses the implicitly defined copy constructor Boo<T>::Boo(Boo<T> const &). Hence, we do not receive an output message.
At (3), we pass instance x to the constructor of instance z, which uses the Boo<T>::Boo(Foo const &) constructor overload.
At (4), we confirm that Boo<int> can be implicitly converted to Foo const & by the compiler and passed into the fun(Foo const &) function.
Question: How can I get (2) to go through the same constructor as (3) does, and why does it not already do that?
If anyone can see what I have missed, I would much appreciate it, were it pointed out to me.
Use a delegating constructor:
template <typename T>
struct Boo : public Foo
{
Boo(Boo<T> const & arg) : Boo(static_cast<Foo const&>(arg)) {};
Boo() { std::cout << "Beep " << sizeof(T) << std::endl; }
Boo(Foo const &) { std::cout << "Boop " << sizeof(T) << std::endl; }
};
The reason this fixes it is that there is no longer an implicit copy constructor, which would have been a better match than casting to Foo const& and using constructor Boo<T>::Boo(Foo const&), and calls it manually.
I have a question about the following code. My compiler is MSVC++ 17 Visual studio version 15.3 with compiler option /std:c++14 (as opposed to /std:c++latest) running in release mode:
struct Bar
{
int a;
std::string b;
Bar() { std::cout << "default\n"; }
Bar(int a, const std::string& b) : a{ a }, b{ b } { std::cout << "direct\n"; }
Bar(int a, std::string&& b) : a{ a }, b{ std::move(b) } { std::cout << "direct move b\n"; }
Bar(const Bar& other) : a{ other.a }, b{ other.b } { std::cout << "const copy\n"; }
Bar(Bar&& other) : a{ std::move(other.a) }, b{ std::move(other.b) } { std::cout << "move\n"; }
Bar& operator=(const Bar& other)
{
a = other.a;
b = other.b;
std::cout << "const assign\n";
return *this;
}
Bar& operator=(Bar&& other)
{
a = std::move(other.a); //would this even be correct?
b = std::move(other.b);
std::cout << "move assign\n";
return *this;
}
};
std::tuple<Bar, Bar> foo()
{
std::string s = "dsdf";
return { { 1, s }, { 5, "asdf" } };
}
int main()
{
Bar a, b;
std::tie(a, b) = foo();
std::cout << a.a << a.b << std::endl;
std::cout << b.a << b.b;
}
The output is:
default
default
direct
direct move b
const copy <-- Why copy? Why not move>
const copy <-- Why copy? Why not move>
move assign
move assign
1dsdf
5asdf
If I change return { { 1, s }, { 5, "asdf" } }; to return { Bar{ 1, s }, Bar{ 5, "asdf" } }; the output changes to:
default
default
direct
direct move b
move
move
move assign
move assign
1dsdf
5asdf
Question: Why isn't a move performed in both cases? Why is the copy constructor called in the first case?
The simplest distillation of your question is why:
std::tuple<Bar> t{{5, "asdf"}};
prints
direct move b
const copy
but
std::tuple<Bar> u{Bar{5, "asdf"}};
prints
direct move b
move
To answer that question, we have to determine what those two declarations actually do. And in order to do that, we have to understand which of std::tuple's constructors get called. The relevant ones are (neither the explicitness and constexprness of each constructor is relevant, so I am omitting them for brevity):
tuple( const Types&... args ); // (2)
template< class... UTypes >
tuple( UTypes&&... args ); // (3)
Initializing with Bar{5, "asdf"} would invoke constructor (3) as the better match (both (2) and (3) are viable, but we get a less cv-qualified reference in (3)), which would forward from the UTypes into the tuple. This is why we end up with move.
But initializing with just {5, "asdf"}, this constructor isn't viable because braced-init-lists have no type that can be deduced. Hence our only option is (2), and we end up with a copy.
The only way to fix this would be to add non-template constructors that take rvalue references to each of the Types. But you would need 2^N-1 such constructors (all but the one that takes all const lvalue references - since that one could be deduced), so instead we end up with a design that works in all cases but is suboptimal. But since you could just specify the type you want on the call site, this isn't a huge defect.
I'm trying to get the deep knowledge about how should I write my copy and move constructors and assignment operators.
In Bjarne Stroustrup's "The C++ Programming Language - 2013" I see the following example of move constructor and move assignment:
template<class T, class A>
vector_base<T,A>::vector_base(vector_base&& a)
: alloc{a.alloc},
elem{a.elem},
space{a.space},
last{a.space}
{
a.elem = a.space = a.last = nullptr; // no longer owns any memory
}
template<class T, class A>
vector_base<T,A>::& vector_base<T,A>::operator=(vector_base&& a)
{
swap(∗this,a);
return *this;
}
(Side note: there seems to be a typo in the book: ::& should be just &, right?)
I suspected it should cause endless recursion, since std::swap() calls move assignment operator:
template<typename T>
void swap(T& lhs, T& rhs)
{
auto temp(lhs);
lhs = std::move(rhs);
rhs = std::move(temp);
}
I've checked it, here's very simple program:
#include <iostream>
using namespace std;
class TestA {
int x;
public:
TestA(int x = 0) : x(x) {
cout << "TestA value ctor " << x << "\n";
}
~TestA() {
cout << "TestA dtor " << x << "\n";
}
TestA(const TestA &a) : x(a.x) {
cout << "TestA copy ctor " << x << "\n";
}
TestA(TestA &&a) : x(a.x) {
cout << "TestA move ctor " << x << "\n";
}
TestA operator=(const TestA &a) {
x = a.getX();
cout << "TestA copy assignment " << x << " = " << a.getX() << "\n";
return *this;
}
TestA &operator=(TestA &&a) {
cout << "TestA move assignment " << x << " = " << a.getX() << "\n";
swap(*this, a);
return *this;
}
int getX() const {
return this->x;
}
};
int main(void) {
TestA a{0};
TestA b{1};
{
TestA c{2};
a = move(c);
}
}
Which produces the following output, so I was right about endless recursion:
TestA value ctor 0
TestA value ctor 1
TestA value ctor 2
TestA move assignment 0 = 2
TestA move ctor 0
TestA move assignment 0 = 2
TestA move ctor 0
TestA move assignment 0 = 2
TestA move ctor 0
...
...
Do I miss something? How can I use swap() inside move assignment?
You're not missing anything, and the accepted answer is wrong. Stroustrup's book is simply bad. There is no free-standing swap() anywhere in chapter 13; it's strongly implied that this swap() is std::swap() (just like copy() is std::copy(), etc.). It's just a bug. Welcome to C++.
What you are missing is that Stroustroup provides a free-function swap(TestA&, TestA&) in the same namespace as the class.
Also, he does not call it as std::swap (neither does your code), but uses an unqualified id and injection of std::swap into the namespace with using ::std::swap;.
Which means the generic version provided by the standard is not used.
At least that is how it should be. Seems that free-standing swap() is really missing. Ouch.