【问题标题】:Creating vector of move-constructed objects创建移动构造对象的向量
【发布时间】:2018-09-19 23:40:43
【问题描述】:

我有一个类,它包含一个在构造过程中移动对象的构造函数:

class SomeClass
{
private:
    const std::unique_ptr<Base> foo;

public:
    template <typename T>
    inline explicit SomeClass(T&& derived) noexcept
     : foo(std::make_unique<T>(derived))
    {
        static_assert(std::is_base_of<Base, T>::value);
    }
};

当我只需要一个实例时,可以毫无问题地构造类的对象:

class Derived : public Base
{
    // ...
};

Derived bar(...);
SomeClass baz(std::move(bar));

// Or

SomeClass baz(Derived(...));

但是我无法将 SomeClass 类型的任何对象放置(或推送)到std::vector&lt;SomeClass&gt;

std::vector<SomeClass> vec;

Derived bar(...);
vec.emplace_back(std::move(bar)); // Does not work.

vec.emplace_back(Derived(...));   // Does not work.

请你解释一下为什么不能放置物体?我认为emplace_back 使用的完美转发将允许就地构造SomeClass 的实例,就像构造单个实例一样。

您能否还解释一下如何修改内容以允许构造std::vector&lt;SomeClass&gt;

我的猜测是,由于构造函数参数是通过 move 传递的,因此它们不会一直转发到 emplace_back 方法中的构造函数。

【问题讨论】:

  • 这不是移动构造函数,也绝不是noexcept
  • SomeClass 有默认构造函数。
  • 它不是移动构造函数,因为它不会通过移动另一个预先存在的实例来构造新实例,但它会在构造函数期间移动给定的参数。我没有看到任何关于 noexcept 的警告。
  • 所以现在重新查看它,我发现您将 Detector 重命名为 SomeClass 但忘记在看起来像成员函数的构造函数的名称上执行此操作。但是,它仍然需要一个 forwarding 引用,它不是移动构造函数。
  • 谢谢,我已编辑以修正错字并澄清我所说的“仅移动构造函数”的意思。

标签: c++ move stdvector unique-ptr emplace


【解决方案1】:

std::vector::emplace_backvalue_type 提出以下要求:

类型要求

-T(容器的元素类型)必须满足MoveInsertableEmplaceConstructible的要求。

类的const 成员隐式删除移动构造函数,即SomeClass 不是MoveInsertable,因为const std::unique_ptr&lt;Base&gt; foo

解决方案:从foo 中删除const

struct Base {};
struct Derived : public Base {};

class SomeClass
{
private:
    std::unique_ptr<Base> foo;

public:
    template <typename T>
    inline explicit SomeClass(T&& derived)
        noexcept(std::is_nothrow_constructible_v<decltype(foo), T&&>) // (1)
     : foo(std::make_unique<T>(std::forward<T>(derived))) // (2)
    {
        static_assert(std::is_base_of<Base, T>::value);
    }
};

int main()
{
    std::vector<SomeClass> vec;

    Derived bar{};
    vec.emplace_back(std::move(bar));

    vec.emplace_back(Derived{}); 
}

Live example.

作为旁注,我建议根据std::is_nothrow_constructible (1) 使noexcept 成为条件,并将std::forward&lt;T&gt;(derived) 传递给std::make_unique 以利用转发引用(2)。

【讨论】:

  • 谢谢。由于 const 而不能移动插入的错误消息通常更明显,但我猜模板消息掩盖了它。感谢您也提供有关使用 std::forward 的提示!
猜你喜欢
  • 2018-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-07
  • 2013-01-24
  • 1970-01-01
  • 2011-11-06
相关资源
最近更新 更多