C++11 对和元组的piecewise_construct 用例?

发布于 2024-11-10 16:16:23 字数 1101 浏览 4 评论 0原文

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

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

例子。我认为我需要一个不可复制的类,但是movebale(转发所需):

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

In N3059 I found the description of piecewise construction of pairs (and tuples) (and it is in the new Standard).

But I can not see when I should use it. I found discussions about emplace and non-copyable entities, but when I tried it out, I could not create a case where I need piecewiese_construct or could see a performance benefit.

Example. I thought I need a class which is non-copyable, but movebale (required for forwarding):

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
};

I then sort-of expected that standard pair-construction would fail:

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

but it did not. Actually, this is what I'd expected anyway, because "moving stuff around" rather then copying it everywhere in the stdlib, is it should be.

Thus, I see no reason why I should have done this, or so:

pair<NoCopy,NoCopy> y(
    piecewise_construct,
    forward_as_tuple(1,2),
    forward_as_tuple(2,3)
); // also fine
  • So, what's a the usecase?
  • How and when do I use piecewise_construct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

厌味 2024-11-17 16:16:23

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

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);

分段构造对的主要用例是将元素放入 mapunordered_map 中:

std::map<int, big> map;
map.emplace(std::piecewise_construct, /*key*/1, /*value*/{2,3});

Not all types can be moved more efficiently than copied, and for some types it may make sense to even explicitly disable both copying and moving. Consider std::array<int, BIGNUM> as an an example of the former kind of a type.

The point with the emplace functions and piecewise_construct is that such a class can be constructed in place, without needing to create temporary instances to be moved or copied.

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});

Compare the above to pair(big(1,2), big(3,4)) where two temporary big objects would have to be created and then copied - and moving does not help here at all! Similarly:

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

The main use case for piecewise constructing a pair is emplacing elements into a map or an unordered_map:

std::map<int, big> map;
map.emplace(std::piecewise_construct, /*key*/1, /*value*/{2,3});
情绪操控生活 2024-11-17 16:16:23

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));
}

One power piecewise_construct has is to avoid bad conversions when doing overload resolution to construct objects.

Consider a Foo that has a weird set of constructor overloads:

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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文