46

N3059 中,我找到了对(和元组)分段构造的描述(并且在新标准中)。

但我看不出什么时候应该使用它。我发现了关于emplace和不可复制实体的讨论,但是当我尝试它时,我无法创建我需要 piecewiese_construct或可以看到性能优势的案例。

例子。我以为我需要一个不可复制的类,但可以移动(转发所需):

struct NoCopy {
  NoCopy(int, int) {};
  NoCopy(const NoCopy&) = delete; // no copy
  NoCopy& operator=(const NoCopy&) = delete; // no assign
  NoCopy(NoCopy&&) {}; // please move
  NoCopy& operator=(NoCopy&&) {}; // please move-assign
};

然后我有点预计标准对构造会失败:

pair<NoCopy,NoCopy> x{ NoCopy{1,2}, NoCopy{2,3} }; // fine!

但它没有。实际上,无论如何,这就是我所期望的,因为“移动东西”而不是在stdlib中的任何地方复制它,是应该的。

因此,我看不出为什么我应该这样做,或者这样:

pair<NoCopy,NoCopy> y(
    piecewise_construct,
    forward_as_tuple(1,2),
    forward_as_tuple(2,3)
); // also fine
  • 那么,用是什么?
  • 我如何以及何时使用piecewise_construct
4

2 回答 2

49

并非所有类型都可以比复制更有效地移动,对于某些类型,甚至显式禁用复制和移动可能是有意义的。考虑std::array<int, BIGNUM>作为前一种类型的示例。

emplace函数的要点piecewise_construct在于,这样的类可以就地构造,而无需创建要移动或复制的临时实例。

struct big {
    int data[100];
    big(int first, int second) : data{first, second} {
        // the rest of the array is presumably filled somehow as well
    }
};

std::pair<big, big> pair(piecewise_construct, {1,2}, {3,4});

将上面的内容与必须创建然后复制pair(big(1,2), big(3,4))两个临时big对象的位置进行比较——移动在这里根本没有帮助!相似地:

std::vector<big> vec;
vec.emplace_back(1,2);

分段构造 pair 的主要用例是将元素放入 amap或 an 中unordered_map

std::map<int, big> map;
map.emplace(std::piecewise_construct, /*key*/1, /*value*/{2,3});
于 2011-05-28T17:40:51.880 回答
0

一种能力piecewise_construct是在进行重载解析以构造对象时避免错误的转换。

考虑一个Foo有一组奇怪的构造函数重载:

struct Foo {
    Foo(std::tuple<float, float>) { /* ... */ }
    Foo(int, double) { /* ... */ }
};

int main() {
    std::map<std::string, Foo> m1;
    std::pair<int, double> p1{1, 3.14};

    m1.emplace("Will call Foo(std::tuple<float, float>)",
               p1);

    m1.emplace("Will still call Foo(std::tuple<float, float>)",
               std::forward_as_tuple(2, 3.14));

    m1.emplace(std::piecewise_construct,
               std::forward_as_tuple("Will call Foo(int, double)"),
               std::forward_as_tuple(3, 3.14));

    // Some care is required, though...
    m1.emplace(std::piecewise_construct,
               std::forward_as_tuple("Will call Foo(std::tuple<float, float>)!"),
               std::forward_as_tuple(p1));
}
于 2021-12-12T15:08:10.413 回答