Bug 52745 - GCC4.7 vector uses copy instead of move constructor
GCC4.7 vector uses copy instead of move constructor
Status: RESOLVED INVALID
Product: gcc
Classification: Unclassified
Component: libstdc++
4.7.0
: P3 normal
: ---
Assigned To: Not yet assigned to anyone
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-03-27 22:43 UTC by Jonathan Rogers
Modified: 2012-03-28 00:11 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Rogers 2012-03-27 22:43:41 UTC
Using GCC 4.7.0, vector seems to prefer copy rather than move when resizing.

The following program produces different (and I think incorrect) results under GCC 4.7.0 vs GCC 4.6.1

#include <iostream>
#include <vector>

struct Stuff
{
    Stuff( ) { }
    Stuff( Stuff&& o ) { std::cout << "Move" << std::endl; }
    Stuff( const Stuff& o ) { std::cout << "Copy" << std::endl; }
};


int main( const int argc, const char** argv )
{

    std::vector< Stuff > stuff;
    std::cout << "1" << std::endl;
    stuff.push_back( Stuff() );
    std::cout << "2" << std::endl;
    stuff.push_back( Stuff() );
    std::cout << "3" << std::endl;
    stuff.push_back( Stuff() );
}

Here is the output under GCC 4.6.1

jonathan@grindserv:~$ g++-4.6.1 -std=c++0x test.cpp
jonathan@grindserv:~$ ./a.out
1
Move
2
Move
Move
3
Move
Move
Move


Here is the output under GCC 4.7.0

jonathan@grindserv:~$ g++-4.7.0 -std=c++0x test.cpp
jonathan@grindserv:~$ ./a.out
1
Move
2
Move
Copy
3
Move
Copy
Copy
Comment 1 Paolo Carlini 2012-03-27 23:06:17 UTC
But Stuff' move-constructor isn't known not to throw...
Comment 2 Jonathan Rogers 2012-03-27 23:13:29 UTC
(In reply to comment #1)
> But Stuff' move-constructor isn't known not to throw...

Okay, so it is a new requirement for move constructors to be marked as nothrow in order for vector to use them for relocation?
Comment 3 Paolo Carlini 2012-03-27 23:21:59 UTC
Otherwise, if the move constructor by chance throws, the push_back cannot have no effects, as required by 23.2.1/10. Actually the requirement holds for all the containers, but only std::vector implements it in 4.7, the other containers (I *think* only std::deque needs work) will follow.
Comment 4 Jonathan Rogers 2012-03-27 23:25:45 UTC
(In reply to comment #3)
> Otherwise, if the move constructor by chance throws, the push_back cannot have
> no effects, as required by 23.2.1/10. Actually the requirement holds for all
> the containers, but only std::vector implements it in 4.7, the other containers
> (I *think* only std::deque needs work) will follow.

In my example code, if you comment out the copy constructor (leaving only the move constructor) then vector will use the (potentially throwing) move constructor.

If what you say is the case, shouldn't vector refuse to use the move constructor?
Comment 5 Paolo Carlini 2012-03-27 23:30:23 UTC
That's known, it's a design choice: in that case you are essentially back to the unsafe 4.6 behavior. Look for 'move_if_noexcept'.
Comment 6 Paolo Carlini 2012-03-27 23:44:44 UTC
Essentially the leeway for the unsafe fallback in the case of Comment #4 is provided by 23.3.6.5/1: "If an exception is thrown by the move constructor of a non-CopyInsertable T, the effects are unspecified".

But really, historically, people simply decided to replace for reallocations unconditional moves with move_if_noexcexpt.
Comment 7 Jonathan Rogers 2012-03-28 00:11:41 UTC
Thanks Paolo. I understand the situation now.

Thanks for your time and sorry the erroneous report!