c++11 emplace_back and push_back syntax with struct

前端 未结 1 1440
無奈伤痛
無奈伤痛 2020-12-25 14:25

I\'m using MSVC, Visual Studio 2013.

Suppose I have a struct:

struct my_pair {
    int foo, bar;
};

And I want to add a bunch of th

相关标签:
1条回答
  • 2020-12-25 14:48

    For v.emplace_back({41,42});, see how to use std::vector::emplace_back for vector<vector<int> >?


    v.emplace_back(41,42); does not work because of some rules in the standard (some emphasis mine):

    Table 101 — Optional sequence container operations

    Expression: a.emplace_back(args)

    Return type: void

    Operational semantics:
    Appends an object of type T constructed with std::forward<Args>(args)....

    Requires: T shall be EmplaceConstructible into X from args. For vector, T shall also be MoveInsertable into X.

    For a type to be EmplaceConstructible,

    § 23.2.1.13

    — T is EmplaceConstructible into X from args, for zero or more arguments args, means that the following expression is well-formed:

    allocator_traits<A>::construct(m, p, args);

    std::allocator_traits::construct() in turn does (if possible) a.construct(p, std::forward<Args>(args)...) (where a is m in the EmplaceConstructible expression).

    a.construct() here is std::allocator::construct(), which calls ::new((void *)p) U(std::forward<Args>(args)...). This is what causes the compile error.

    U(std::forward<Args>(args)...) (take note of the use of direct initialization) will find a constructor of U which accepts the forwarded arguments. However, in your case, my_pair is an aggregate type, which can only be initialized with braced-initialization syntax (aggregate initialization).


    v.emplace_back(my_pair{41,42}); works because it calls either the implicitly generated default copy constructor or move constructor (note that these two may not always be generated). A temporary my_pair is first constructed which goes through the same process as that of v.emplace_back(41,42);, only that the argument is an r-value my_pair.


    ADDITIONAL 1:

    And why does push_back(T&&) work without addition of the struct's name?

    It's because of push_back's signatures. push_back()'s argument isn't deduced, which means by doing push_back({1, 2}), a temporary object with the type of the vector's element type is first created and initialized with {1, 2}. That temporary object will then be the one that is passed to push_back(T&&).


    Should I just stick with push_back? Is there any reason to use emplace_back(structname{1,2,3}) instead of push_back({1,2,3}) because it will end up calling push_back(T&&) anyway, and is easier to type?

    Basically, emplace* functions is meant to optimize and remove the cost of creating temporaries and copying or move constructing objects when inserting them. However, for the case of aggregate data types where doing something like emplace_back(1, 2, 3) isn't possible, and the only way you could insert them is through creating a temporary then copying or moving, then by all means prefer the leaner syntax, and go for push_back({1,2,3}), where it would basically have the same performance as that of emplace_back(structname{1,2,3}).

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