Вызывает ли vector <T>:: push_back () какой-либо соответствующий конструктор своего типа T? - PullRequest
0 голосов
/ 25 декабря 2018

Я недавно использовал reference_wrapper вот так:

#include <iostream>
#include <vector>
#include <functional>
#include <memory>

struct A {
};

struct B {
    B() {};
    B(A& aA) {};
    B(const B&) = default;
};

int main () {
    A a;
    B b;

    std::vector<std::reference_wrapper<B>> rvector;
    rvector.push_back(std::reference_wrapper<B>(b)); // (1)
    rvector.push_back(b); // (2)

1 и 2, оба компилируются и работают просто отлично, и мне интересно, какой из них правильный!Поэтому я подумал, что следующее тоже может сработать:

    std::vector<B> bvector;
    bvector.push_back(a); // (3)
    bvector.push_back(b); // (4)
    std::cout << bvector.size() << "\n";

да, это работает!Итак, я пришел к выводу, что push_back просто вызывает конструктор типа T с заданным параметром. Документация , хотя упоминается, что параметр имеет тип T и, в конечном счете, ctor копирования / перемещения.

Когда я пробовал 1 и 2 с shared_ptr, хотя:

    std::vector<std::shared_ptr<B>> pvector;
    pvector.push_back(std::shared_ptr<B>(new B())); // (5)
    pvector.push_back(new B()); // (6)

Я получаю

no matching function for call to 'std::vector<std::shared_ptr<B> >::push_back(B*)'
  • Почему 2 и даже 3 работают, а 6 нет?
  • Должен быть shared_ptr<B> конструктор, который принимает B* в качестве параметране так ли?Итак, почему 6 не компилируется (так как 3 не компилируется)?
  • Поскольку 3 компилируется и работает просто отлично, было бы нормально использовать и рассчитывать на это (если это не был плохой подход, так как естьemplace_back)?

Ответы [ 3 ]

0 голосов
/ 25 декабря 2018

Почему 2 и даже 3 работают, а 6 нет?

std::vector::push_back принимает T в качестве параметра, тогда он будет работать, если выВы передаете что-то, что может быть неявно преобразовано в T.

(2) работает, потому что B может преобразоваться в std::reference_wrapper<B> неявно.(3) работает, потому что A может конвертироваться в B неявно.(6) не работает, потому что B* не может конвертироваться в shared_ptr<B> неявно.Обратите внимание, что конструктор shared_ptr, использующий необработанные указатели , помечается как explicit.

Поскольку 3 компилируется и работает просто отлично, можно ли использовать и рассчитывать наэто (если это не был плохой подход, так как есть emplace_back)?

Да, вы можете использовать его, но учтите, что emplace_back иногда более эффективен;он создаст элемент непосредственно на месте без какого-либо неявного преобразования вместо создания временного T, а затем переместит его в vector (как push_back).

0 голосов
/ 25 декабря 2018

push_back принимает T const& или T&&.

Так что если у нас есть vector<X>, push_back(expr) работает, если X const& x=expr; компилируется или X&& x=expr; компилируется, и это неЭто неоднозначно, что лучше, и перемещение / копирование из аргумента разрешено.

Они компилируются для ваших первых случаев, но не ваш общий ptr из ptr, потому что X x=expr; не вызывает explicitконструкторы.

Вы можете vec.emplace_back(expr), если хотите рассмотреть явные конструкторы.

0 голосов
/ 25 декабря 2018

Конструктор std::reference_wrapper является конвертирующим конструктором , который допускает неявное преобразование из B в std::reference_wrapper<B>, и поэтому (2) работает.

Однако конструктор (3) из std::shared_ptr равен explicit, поэтому вам необходимо явно указать std::shared_ptr<B> в (5).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...