Oct 3, 2013 at 7:57am UTC
Hello
I create a class with a move constructor as followed:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#include <iostream>
#include <string>
using namespace std;
class Base{
public :
Base(const string& str):m_Str(str)
{cout << m_Str << ": Use COPY constructor \n" ;};
Base(string&& str):m_Str(move(str))
{cout << m_Str <<": Use MOVE constructor \n" ;};
private :
string m_Str;
};
int main(int argc, char * argv[])
{
Base b("example" );
system("pause" );
return 0;
}
However when I create the object "b" the COPY constructor is used.
When I write instead:
Base b((string)"example" );
then the it works, the MOVE constructor is used. The problem may be linked to the conversion of char array and string...
Anyone know where lies the problem? I do not have this problem with VS2012 but my company uses VS2010. Thank you.
Last edited on Oct 3, 2013 at 7:57am UTC
Oct 3, 2013 at 8:42am UTC
looks like VS2010 does not support implicit moving of implicitly created l-value variables.
Techncally even
Base b((string)"example" );
may use copy constructor. to be sure that move constructor is used use std::move() with argument.
EDIT:
http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx
Look under R-value references section. It describes it.
Last edited on Oct 3, 2013 at 8:46am UTC
Oct 3, 2013 at 8:43am UTC
> I do not have this problem with VS2012
VS 2012 is right.
Base b("example" );
is
direct initialization
http://en.cppreference.com/w/cpp/language/direct_initialization
T object ( arg );
(1) initialization with a nonempty parenthesized list of expressions
...
The effects of direct initialization are:
If T is a class type, the constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.
...
... direct-initialization considers all constructors and implicit conversion sequences.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Base{
public :
Base(const string& str):m_Str(str)
{cout << m_Str << ": Use COPY constructor \n" ;};
Base(string&& str):m_Str(move(str))
{cout << m_Str <<": Use MOVE constructor \n" ;};
private :
string m_Str;
};
int main()
{
Base b("example" ); // direct initialization: Use MOVE constructor
// http://en.cppreference.com/w/cpp/language/copy_initialization
Base b2 = string("second example" ) ; // copy initialization: Use MOVE constructor
// copy initialization is less permissive than direct initialization
// Base b3 = "third example" ; // *** error
}
http://coliru.stacked-crooked.com/a/c215d28ffae2a184
Ideally, user-defined move constructors should not throw
Base(string&& str) noexcept ( is_nothrow_move_constructible<string>::value ) ;
See:
http://en.cppreference.com/w/cpp/utility/move_if_noexcept
> Techncally even Base b((string)"example"); may use copy constructor.
No. Not if
Base::Base( string&& )
is accessible.
Last edited on Oct 3, 2013 at 8:54am UTC
Oct 3, 2013 at 9:14am UTC
Thank you a lot for your reply
Canh
Oct 3, 2013 at 9:27am UTC
I'm sorry, I should have mentioned this earlier.
Even though we are printing "Use MOVE constructor", and have loosely referred to the constructor that moves a string as the 'move constructor',
technically the move constructor is the implicitly defined
Base( Base&& other )noexcept ;
http://en.cppreference.com/w/cpp/language/move_constructor
Base( string&& str ) /* noexcept */
is just a constructor that takes an rvalue reference to a string.
Last edited on Oct 3, 2013 at 9:30am UTC