-4

How this push_back overload implemented?

void push_back( T&& value );

Or maybe one possible implementation?

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
lightrek
  • 951
  • 3
  • 14
  • 30
  • 2
    Just look in the library headers on your computer, I don't see what pasting some implementation here is supposed to be good for. – Baum mit Augen Apr 19 '17 at 14:05
  • 1
    One way: `data[last_element + 1] = std::move(value);` – NathanOliver Apr 19 '17 at 14:05
  • 1
    @JerryCoffin: nope - `value` itself is an lvalue. You need `std::move` to make `value` an rvalue reference. – Vittorio Romeo Apr 19 '17 at 14:08
  • 4
    @JerryCoffin An rvalue reference is not an rvalue. – François Andrieux Apr 19 '17 at 14:08
  • 2
    @JerryCoffin No, it's cast to rvalue; and `value` is an lvalue, as a named variable. – songyuanyao Apr 19 '17 at 14:08
  • 1
    @JerryCoffin See [this](http://en.cppreference.com/w/cpp/utility/move). A rvaule reference is an lvalue as it is named and you can take it's address. You must use `std::move` to cast it back to a xvalue. – NathanOliver Apr 19 '17 at 14:10
  • @JerryCoffin: No, it makes the expression an xvalue, which the expression `value` certainly is _not_ already. Further reading: "[What is std::move(), and when should it be used?](http://stackoverflow.com/q/3413470/560648)" – Lightness Races in Orbit Apr 19 '17 at 14:10
  • Why my post has so many down votes? – lightrek Apr 19 '17 at 14:28
  • You'd think I'd learn better than to post (or even comment) before I was awake in the morning--but you'd obviously be wrong! – Jerry Coffin Apr 19 '17 at 14:36
  • @lightrek: Which aspect of this function's implementation is confusing to you? The part where it potentially reallocates storage, or the part where it constructs the new `T`? – Nicol Bolas Apr 19 '17 at 16:01
  • @NicolBolas I just want to check the standard library implementation and I think I could learn better coding style from it. I know the universal referencing. – lightrek Apr 19 '17 at 21:11
  • @lightrek: "*I know the universal referencing*" Not very well, apparently, since 1) The term is "[forwarding reference](http://en.cppreference.com/w/cpp/language/reference#Forwarding_references)", and 2) that's not a forwarding reference. `push_back` doesn't use template argument deduction, so no forwarding references are involved. – Nicol Bolas Apr 19 '17 at 21:35
  • @NicolBolas I think that's a template, thus, it's a forward referencing: http://en.cppreference.com/w/cpp/container/vector/push_back – lightrek Apr 20 '17 at 04:32
  • @lightrek: A forward reference is a "function parameter of a function template declared as rvalue reference to cv-unqualified type ***template parameter of that same function template***:" `push_back`'s parameter `T` is not a template parameter of the function; it's a template parameter of the *class*. – Nicol Bolas Apr 20 '17 at 13:11
  • @NicolBolas Yes, you are right. I noticed that. Only T&& will be rvalue reference, even a const will destroy it. By the way, it is not easy to check the original source file, hard to understand, for instance: void push_back(value_type&& _Val) – lightrek Apr 20 '17 at 19:31

2 Answers2

0

One possible implementation:

template <typename T, typename Allocator>
void
vector<T, Allocator>::push_back(T&& _element) 
{
    if (size() == capacity()) reallocate(capacity() * 2);

    construct(data()[size()], std::move(_element));
    ++size_val;

    update_vector();
}

construct() would call T::T(T&&) if there is one. Otherwise it would call T::T(const T&).

See https://en.cppreference.com and search construct for more information

0

A very simple implementation would be:

template <typename T, typename Allocator>
void vector<T, Allocator>::push_back(T&& _element)
{
  emplace_back(std::move(_element));
}

If the value type T has a move constructor (that is, T::T(T&&)), doing it this way can be more efficient than using its copy constructor. A std::vector does require its value type to be copy-constructible, so this will use the copy constructor if there is no move constructor.

A common case where this makes a difference is when a class contains a pointer to a large buffer or structure. If we need a copy initialized to the same data that we can modify, and the original has to remain valid, we have to make an expensive deep copy. On the other hand, when we know the source is a temporary that is about to be thrown away, we can just swap its contents with those of an empty object. That lets us re-use the same memory with no reallocations or deep copies of its contents.

Davislor
  • 14,674
  • 2
  • 34
  • 49