I have a function that deals with a movable-only instance that is a wrapper around something else. That object provides means of access to the wrapped object and some checks which require it to be non-copyable. (Use case is a table of values, where the dtor of the wrapper should assert that all values were were accessed)
I defined a custom ctor from the wrapped type and implemented the move ctor/assignment.
However I'm getting an error due to an attempted copy: error: 'Movable::Movable(Movable&)' is private within this context
It works fine in C++11 but I need portability to C++03. How can I do this without an explicit instantiation of the wrapper and moving it into the function?
MWE:
#include <boost/move/move.hpp>
#include <iostream>
class Movable{
BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
public:
int i;
Movable(int j):i(j){}
Movable(BOOST_RV_REF(Movable) other) // Move constructor
: i(boost::move(other.i))
{}
Movable& operator=(BOOST_RV_REF(Movable) other) // Move assignment
{
if(this != &other)
i = boost::move(other.i);
return *this;
}
};
void bar(Movable mov){
mov.i = 22;
std::cout << mov.i;
}
int main(int argc, char* argv[])
{
bar(5);
return 0;
}
The problem appears to be that the implicit conversion constructor interferes with the copy-constructor suppression.
Either use
Movable m(5);
bar(boost::move(m));
Or
bar(Movable(5));
To make sure that you select for the explicit constructor. Obviously, that means you can even mark it explicit:
Live On Coliru
#include <boost/move/move.hpp>
#include <iostream>
class Movable{
BOOST_MOVABLE_BUT_NOT_COPYABLE(Movable)
public:
int i;
explicit Movable(int j):i(j){}
Movable(BOOST_RV_REF(Movable) other) // Move constructor
: i(boost::move(other.i))
{}
Movable& operator=(BOOST_RV_REF(Movable) other) // Move assignment
{
if(this != &other)
i = boost::move(other.i);
return *this;
}
};
void bar(Movable mov){
std::cout << mov.i << " ";
mov.i = 22;
std::cout << mov.i << "\n";
}
int main() {
Movable m(5);
bar(boost::move(m));
bar(Movable(6));
}
Prints
5 22
6 22
Related
I'm trying to understand how the copy assignment constructor works in c++. I've only worked with java so i'm really out of my waters here. I've read and seen that it's a good practice to return a reference but i don't get how i should do that. I wrote this small program to test the concept:
main.cpp:
#include <iostream>
#include "test.h"
using namespace std;
int main() {
Test t1,t2;
t1.setAge(10);
t1.setId('a');
t2.setAge(20);
t2.setId('b');
cout << "T2 (before) : " << t2.getAge() << t2.getID() << "\n";
t2 = t1; // calls assignment operator, same as t2.operator=(t1)
cout << "T2 (assignment operator called) : " << t2.getAge() << t2.getID() << "\n";
Test t3 = t1; // copy constr, same as Test t3(t1)
cout << "T3 (copy constructor using T1) : " << t3.getAge() << t3.getID() << "\n";
return 1;
}
test.h:
class Test {
int age;
char id;
public:
Test(){};
Test(const Test& t); // copy
Test& operator=(const Test& obj); // copy assign
~Test();
void setAge(int a);
void setId(char i);
int getAge() const {return age;};
char getID() const {return id;};
};
test.cpp:
#include "test.h"
void Test::setAge(int a) {
age = a;
}
void Test::setId(char i) {
id = i;
}
Test::Test(const Test& t) {
age = t.getAge();
id = t.getID();
}
Test& Test::operator=(const Test& t) {
}
Test::~Test() {};
I can't seem to understand what i should be putting inside operator=(). I've seen people returning *this but that from what i read is just a reference to the object itself (on the left of the =), right? I then thought about returning a copy of the const Test& t object but then there would be no point to using this constructor right? What do i return and why?
I've read and seen that it's a good practice to return a reference but i don't get how i should do that.
How
Add
return *this;
as the last line in the function.
Test& Test::operator=(const Test& t) {
...
return *this;
}
Why
As to the question of why you should return *this, the answer is that it is idiomatic.
For fundamental types, you can use things like:
int i;
i = 10;
i = someFunction();
You can use them in a chain operation.
int j = i = someFunction();
You can use them in a conditional.
if ( (i = someFunction()) != 0 ) { /* Do something */ }
You can use them in a function call.
foo((i = someFunction());
They work because i = ... evaluates to a reference to i. It's idiomatic to keep that semantic even for user defined types. You should be able to use:
Test a;
Test b;
b = a = someFunctionThatReturnsTest();
if ( (a = omeFunctionThatReturnsTest()).getAge() > 20 ) { /* Do something */ }
But Then
More importantly, you should avoid writing a destructor, a copy constructor, and a copy assignment operator for the posted class. The compiler created implementations will be sufficient for Test.
We return a reference from the assignment operator so we can do some cool tricks like #SomeWittyUsername shows.
The object we want to return a reference to is the one who the operator is being called on, or this. So--like you've heard--you'll want to return *this.
So your assignment operator will probably look like:
Test& Test::operator=(const Test& t) {
age = t.getAge();
id = t.getID();
return *this;
}
You may note that this looks strikingly similar to your copy-constructor. In more complicated classes, the assignment operator will do all the work of the copy-constructor, but in addition it'll have to safely remove any values the class was already storing.
Since this is a pretty simple class, we have nothing we need to safely remove. We can just re-assign both of the members. So this will be almost exactly the same as the copy-constructor.
Which means that we can actually simplify your constructor to just use the operator!
Test::Test(const Test& t) {
*this = t;
}
Again, while this works for your simple class, in production code with more complicated classes, we'll usually want to use initialization lists for our constructors (read here for more):
Test::Test(const Test& t) : age(t.getAge()), id(t.getId()) { }
Returning reference to the original object is needed for support of nested operations.
Consider
a = b = c
Mechanism for this is well explained here: Template "copy constructor" does not prevent compiler-generated move constructor, but I would like to better undestand why it is made this way. I understand that move constructor is not generated even if any other constructor is written by the programmer, because it is an indication that construction of object is non trivial and auto generated constructor will probably be wrong. Then why templated constructors that have the same signature as copy constructors are not simply named copy constructors?
Example:
class Person {
public:
template<typename T>
Person(T&& t) : s(std::forward<T>(t)) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
Person(int n) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
// No need to declare copy/move constructors as compiler will do this implicitly
// Templated constructor does not inhibit it.
//Person(const Person&) = default;
//Person(Person&&) = default;
private:
std::string s;
};
and then:
Person p("asd"); // OK!
//Person p4(p); // error as Person(T&&) is a better match
if I make p const:
const Person p("asd");
Person p4(p); // thats ok, generator constructor is a better match
but if I explicitly delete even a move constructor with:
Person(Person&&) = delete;
then auto generation of constructors is inhibited.
You understand wrong.
struct noisy {
noisy() { std::cout << "ctor()\n"; }
noisy(noisy&&) { std::cout << "ctor(&&)\n"; }
noisy(noisy const&) { std::cout << "ctor(const&)\n"; }
noisy& operator=(noisy&&) { std::cout << "asgn(&&)\n"; return *this; }
noisy& operator=(noisy const&) { std::cout << "asgn(const&)\n"; return *this; }
};
struct test {
noisy n;
test(int x) { (void)x; }
};
test has generated move/copy construct/assignment.
Live example.
A copy/move construct/assignment written by a programmer results in the other ones being suppressed.
Now, writing a constructor suppresses the zero-argument constructor. That may be why you are confused.
Templated constructors with the same signature as copy constructors are not copy constructors because the standard says so.
As it happens, templated code is rarely the correct code for a copy or move constructor/assignment.
The fact that forwarding references often grab self& and self const&& copy/move over the actual copy/move operations is a problem. C++ isn't perfect.
Usually the way to avoid this is:
template<class T,
class=std::enable_if_t<
!std::is_same<std::decay_t<T>, Person>::value
>
>
Person(T&& t) : s(std::forward<T>(t)) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
or !std::is_base_of<Person, std::decay_t<T>>::value which covers some other situations (like inheriting constructors).
For the program code below, I have to write the the same code inside the pair of member functions which receiving rvalue and lvalue references.
My aim is to use only one from the pair (e.g.; only use the rvalue accepting ones), and the others. I read the reference of std::forward, as far as I understood, it looks like it is for this purpose. But, when I delete the lvalue reference taking ones, I get the following compiler error.
'TestClass::TestClass(const TestClass &)': cannot convert argument 1 from 'std::wstring' to 'std::wstring &&'
How do I prevent this code duplication?
#include <iostream>
#include <string>
class TestClass
{
public:
TestClass(const std::wstring & Text)
: Text(Text)
{
std::wcout << L"LValue Constructor : " << Text << std::endl;
/*Some code here...*/
}
TestClass( std::wstring && Text)
: Text(std::forward<std::wstring>(Text))
{
std::wcout << L"RValue Constructor : " << this->Text << std::endl;
/*Same code here...*/
}
TestClass(const TestClass & Another)
: Text(Another.Text)
{
std::wcout << L"Copy Constructor : " << Text << std::endl;
/*Some code here...*/
}
TestClass( TestClass && Another)
: Text(std::forward<std::wstring>(Another.Text))
{
std::wcout << L"Move Constructor : " << Text << std::endl;
/*Same code here...*/
}
private:
std::wstring Text;
};
int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
std::wstring Argument(L"Testing Copy");
TestClass Class1Copy(Argument);
TestClass Class1Move(L"Testing Move");
TestClass Class2Copy(Class1Copy);
TestClass Class2Move(std::move(Class1Move));
_wsystem(L"pause");
return 0;
}
Output:
LValue Constructor : Testing Copy
RValue Constructor : Testing Move
Copy Constructor : Testing Copy
Move Constructor : Testing Move
Press any key to continue . . .
If move construction is expected to be extremely cheap, you can take by value and move-from the value. This does exactly 1 more move than a pair of copy and move overloads.
If you want optimal efficiency, and/or if move construction is cheaper but not cheap enough to neglect, you can forward:
template<class T>
std::decay_t<T> copy(T&& t) {
return std::forward<T>(t);
}
class TestClass {
public:
TestClass(std::wstring const& Text)
TestClass( copy(Text) )
{}
TestClass(TestClass const& o)
: TestClass( o.Text )
{}
TestClass(TestClass&& o)
: TestClass( std::move(o).Text ) // pattern does the right thing more often than `std::move(o.Text)` does.
{}
// only "real" ctor:
TestClass( std::wstring&& Text)
: Text(std::forward<std::wstring>(Text))
{
std::wcout << L"RValue Constructor : " << this->Text << std::endl;
/*Code here...*/
}
// ...
now everything forwards down to the one constructor.
You can even mix the two techniques: use by-value for std::wstring (as we know that is cheap-to-move) and do forwarding stuff for the TestClass code (or anything less likely to be stable).
You can take by value and then move. Then you only need N overloads, not 2N:
TestClass(std::wstring Text)
: Text(std::move(Text))
{
}
You can avoid the copy constructor and move constructor duplication by writing nothing at all; the compiler will generate them by default in this case.
I don't think you can do that since the function's signatures determine when and where they are used. It's like a copy constructor and an assignment operator. They do somewhat similar things but the compiler calls the appropriate one basee on context.
If you want to avoid reusing code, just factor out the commonality into a separate function.
Right when I thought I understood what std::move and move constructors do, I tried to write some unit test, actually testing the move constructor for some class...
To my surprise I found, that I cannot think of a way to construct code which actually calls the move constructor. Worse, I cannot even set a breakpoint in the body of the move constructor (in VS2013 community edition, debug, 64bit build).
Wondering if this is a compiler peculiarity, I knocked up some small test code on my freebsd virtual machine, using clang (3.4.1). There, too I fail to find a way to get that move constructor invoked.
#include <iostream>
#include <stdint.h>
#include <string>
#include <algorithm>
#include <functional>
#include <ctype.h>
#include <locale>
void InPlaceToUpper( std::string& target )
{
std::transform(target.begin(), target.end(), target.begin(), ::toupper);
}
void InPlaceToLower( std::string& target )
{
std::transform(target.begin(), target.end(), target.begin(), ::tolower);
}
std::string ToUpper( const std::string& s )
{
std::string result;
result.resize(s.length());
std::transform(s.begin(), s.end(), result.begin(), ::toupper);
return result;
}
std::string ToLower( const std::string& s)
{
std::string result;
result.resize(s.length());
std::transform(s.begin(), s.end(), result.begin(), ::tolower);
return result;
}
class CFoo
{
std::string m_value;
public:
CFoo()
: m_value()
{
std::cout << "CFoo() called." << std::endl;
}
CFoo(const char *value)
: m_value(value)
{
std::cout << "CFoo(const char *) called." << std::endl;
}
CFoo(const std::string& value )
: m_value(value)
{
std::cout << "CFoo(const std::string&) called." << std::endl;
}
CFoo(const CFoo& other )
: m_value(other.m_value)
{
std::cout << "CFoo() copy constructor called." << std::endl;
}
CFoo(CFoo&& other )
: m_value(std::move(other.m_value))
{
std::cout << "CFoo() move constructor called." << std::endl;
std::cout << "other.m_value = " << other.m_value.c_str() << std::endl;
}
~CFoo()
{
std::cout << "~CFoo() called." << std::endl;
}
const CFoo& operator=( const CFoo& other )
{
std::cout << "CFoo copy assignment operator called." << std::endl;
if( &other != this )
{
m_value = other.m_value;
}
return *this;
}
const CFoo& operator=( CFoo&& other )
{
std::cout << "CFoo move assignment operator called." << std::endl;
if( &other != this )
{
m_value = std::move(other.m_value);
}
return *this;
}
CFoo ToUpper()
{
return CFoo(::ToUpper(m_value));
}
CFoo ToLower()
{
return CFoo(::ToLower(m_value));
}
const char * ToString() const
{
return m_value.c_str();
}
};
int main( int argc, const char *argv[] )
{
{
CFoo foo;
CFoo foo1("Hello World");
CFoo foo2 = CFoo("Hello again World!");
CFoo foo3(CFoo("Bye world"));
CFoo foo4 = CFoo("Bye again world");
CFoo foo5 = foo4.ToUpper();
CFoo foo6 = foo4.ToLower();
foo6 = foo4.ToUpper();
std::cout << "foo4: " << foo4.ToString() << std::endl;
foo6 = CFoo("Well well well");
}
return 0;
}
My apologies if the code is not as short as it might possibly be. But there are only a few spots to look at, namely my efforts to get the move constructor invoked in main() and the definition of the various constructors in class Foo.
I am aware of compiler settings which allow turning off RVO and stuff but for the purpose of using the feature "move constructor" in performance aware code, there should be a classic example of when it gets invoked. If that is not the case, I will probably decide not to even bother using move constructors at all.
To answer the question, you can tell me a line I can write in main() which gets the move constructor of CFoo called. Or you can tell me what I am doing wrong.
Does std::string support being moved like that? Maybe this is why my efforts fail?
Thanks, in advance.
In all your attempts to use the move constructor it is being elided, so that e.g. CFoo foo = CFoo(blah); is simply equivalent to CFoo foo(blah); which doesn't need to use the move constructor. This is a Good Thing because the compiler is optimising away the need for any copy or move to happen at all.
To see the move constructor being used try:
CFoo f1;
CFoo f2 = std::move(f1);
This constructs f2 from an rvalue, and nothing can be elided, so the move constructor will be used.
First of all, there is an error in std::string ToUpper(const std::string& s), namely there is no space in result. C++ algorithms do not grow their target containers automatically. You must either allocate space yourself, or use a inserter adaptor.
To make space in out, e.g. do this:
result.resize(s.length());
After it the move assignment operator called for:
foo6 = foo4.ToUpper();
foo6 = CFoo("Well well well");
The move constructor is called whenever an object is initialized from xvalue of the same type, which includes:
initialization, T a = std::move(b); or T a(std::move(b));, where b is of type T
function argument passing: f(std::move(a));, where a is of type T and f is void f(T t)
function return: return a; inside a function such as T f(), where a is of type T which has a move constructor.
For more see move constructors on cppreference.com.
I have the following simple test code.
#include <stack>
#include <iostream>
#include "boost/pool/pool_alloc.hpp"
struct Frame
{
uint32_t i{};
Frame(uint32_t _i) : i(_i) {}
Frame(const Frame& f)
{
std::cout << "Copy constructor" << std::endl;
i = f.i;
}
Frame(Frame&& f)
{
std::cout << "Move constructor" << std::endl;
std::swap(i, f.i);
}
};
int main(int argc, char* argv[])
{
{
std::stack<Frame, std::deque<Frame>> stack;
Frame f(0);
stack.push(std::move(f)); // Move constructor
stack.push(Frame(1)); // Move constructor
}
{
std::stack<Frame, std::deque<Frame, boost::pool_allocator<Frame>>> stack;
Frame f(0);
stack.push(std::move(f)); // Copy constructor
stack.push(Frame(1)); // Copy constructor
}
return 0;
}
When I compile this code with either Clang or GCC, it gives me the following output:
Move constructor
Move constructor
Copy constructor
Copy constructor
Why does using boost::pool_allocator prevent the compiler from using the move constructor?
Am I missing something?
pool_allocator does not perfect forward the arguments to construct: It simply takes a const reference to the value type and passes that on as the initializer for placement new.
That is because pool_allocator has not been updated for C++11 yet.