vector <t> :: push_back()是否调用任何类型为T的匹配构造函数?

时间:2018-12-25 02:42:57

标签: c++ c++11 vector

我最近像这样使用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构造函数。尽管Documentation提到参数的类型为T,最后是复制/移动ctor类型。

当我使用shared_ptr尝试1和2时:

    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 :(得分:1)

Constructor of std::reference_wrapperconverting constructor,它允许从Bstd::reference_wrapper<B>的隐式转换,这就是(2)起作用的原因。

但是constructor (3) of std::shared_ptrexplicit,因此您必须在(5)中明确指定std::shared_ptr<B>

答案 1 :(得分:1)

  

为什么2甚至3可以工作但6不能工作?

std::vector::push_backT作为参数,如果您传递的内容可以隐式转换为T,则它将起作用。

(2)之所以有效,是因为B可以隐式转换为std::reference_wrapper<B>。 (3)之所以有效,是因为A可以隐式转换为B。 (6)不起作用,因为B*无法隐式转换为shared_ptr<B>。请注意,the constructor of shared_ptr taking raw pointers被标记为explicit

  

由于3可以编译并正常工作,因此可以使用它并依靠它吗(如果因为有emplace_back,这不是一个坏方法)?

是的,您可以使用它,但是请注意,emplace_back有时更有效;它将直接在原位构造元素而不进行任何隐式转换,而不是构造临时T并将其移动到vector中(作为push_back)。

答案 2 :(得分:1)

push_backT const&T&&

因此,如果我们有一个vector<X>,则push_back(expr)可以在X const& x=expr;X&& x=expr;进行编译的情况下工作,并且匹配性更好,移动/复制也不是模棱两可允许使用自变量。

那些是为您的第一种情况编译的,但不是从ptr共享的ptr,因为X x=expr;不会调用explicit构造函数。

如果要考虑使用显式构造函数,则可以vec.emplace_back(expr)