Standard library containers producing a lot of copies on rvalues in GCC

前端 未结 5 1339
隐瞒了意图╮
隐瞒了意图╮ 2020-12-30 23:49

I\'m writing a app for both linux & windows, and noticed that the GCC build is producing a lot of useless calls to the copy constructor.

Here\'s an example code

相关标签:
5条回答
  • 2020-12-31 00:27

    Try this then:

    std::vector<A> vec_a;
    vec_a.reserve(3);
    for (size_t i = 0; i < 3; ++i)
      vec_a.push_back(A());
    

    What you're trying to do is force the initialization process to use construct+move for each value instead of construct and then copy/copy/copy. These are just different philosophies; the libraries authors couldn't possibly know which is going to be the best for any given type.

    0 讨论(0)
  • 2020-12-31 00:27

    You can add special (cheap) case to copy ctor algorithm when copying default constructed object to "this" object. It's just a workaround, however, the behaviour is strange enough. Both compilers (libraries) create a temporary object on the stack, then gcc copies this temporary to the targets 3 times; msvc recreates temporary object 3 times (!) (on the stack too) and moves 3 timesn to targets. I don't understand why they don't create objects directly in place.

    0 讨论(0)
  • 2020-12-31 00:39

    Looks like the problem is that the version of g++ that you have does not have a C++0x fully compliant library. In particular, in C++03, the size constructor of std::vector has the following signature:

    // C++ 03
    explicit vector(size_type n, const T& value = T(),
    const Allocator& = Allocator());
    

    With that function signature and your call, a temporary is created, then bound by the constant reference and copies of it are created for each one of the elements.

    while in C++0x there are different constructors:

    // C++0x
    explicit vector(size_type n);
    vector(size_type n, const T& value, const Allocator& = Allocator());
    

    In this case, your call will match the first signature, and the elements should be default constructed with placement new over the container (as @Howard Hinnant correctly points out in his answer the compiler should not call the move constructor at all).

    You can try and check if more recent versions of g++ have an updated standard library, or you can work around the issue by manually adding the elements:

    std::vector<A> v;
    v.reserve( 3 );     // avoid multiple relocations
    while (v.size() < 3 ) v.push_back( A() );
    
    0 讨论(0)
  • 2020-12-31 00:40

    Both implementations (Visual C++ 2010 and GCC 4.4.0) are in error. The correct output is:

    default
    default
    default
    

    This is specified in 23.3.5.1 [vector.cons]/4:

    Requires: T shall be DefaultConstructible.

    The implementation is not allowed to assume that A is either MoveConstructible nor CopyConstructible.

    0 讨论(0)
  • 2020-12-31 00:40

    I think, that all 3 variants do not violate C++0x draft. It requires following: 1. Constructs a vector with n value-initialized elements 2. T shall be DefaultConstructible 3. Linear in n

    All 3 variants satisfy 1, as default + copy, default + move are equivalent to default All 3 variants satisfy 3 All 3 variants satisfy 2: they work for DefaultConstructible types. Specific algorithm can be used for Moveable types. It is a general practice in STL to use different versions of algorithms for types with different capabilities.

    0 讨论(0)
提交回复
热议问题