C++11 中聚合初始化何时有效?

发布于 2024-11-14 09:20:23 字数 1133 浏览 5 评论 0 原文

假设我们有以下代码:

#include <iostream>
#include <string>

struct A
{
  A() {}
  A(const A&) { std::cout << "Copy" << std::endl; }
  A(A&&) { std::cout << "Move" << std::endl; }
  std::string s;
};

struct B
{
  A a;
};

int main()
{
  B{A()};
}

在这里,我相信 struct A 不是一个聚合,因为它既有重要的构造函数,也有一个 std::string 成员,我认为这不是一个集合。这可能意味着 B 也不是聚合。

但我可以聚合初始化 B。此外,这可以在不调用复制或移动构造函数的情况下完成(例如 ideone)。

这种行为似乎是一种有用的优化,特别是对于将没有廉价移动的大型堆栈类型组合在一起。

我的问题是:这种聚合初始化在 C++0x 下什么时候有效?

编辑+跟进问题:

下面的 DeadMG 回答如下:

这根本不是聚合初始化,而是统一初始化,在这种情况下基本上意味着调用构造函数,并且没有复制或移动可能是由 RVO 和 NRVO 完成的。

请注意,当我将 B 更改为以下内容时:

struct B
{
  A a;
  B(const A& a_) : a(a_) {}
  B(A&& a_) : a(std::move(a_)) {}
};

执行移动。

因此,如果这只是统一初始化并且只是调用构造函数而不执行任何特殊操作,那么我如何编写一个允许省略移动的构造函数?

或者,当有效时,GCC 是否只是不消除此处的移动,如果是这样,是否有编译器和优化设置可以消除移动?

Lets say we have the following code:

#include <iostream>
#include <string>

struct A
{
  A() {}
  A(const A&) { std::cout << "Copy" << std::endl; }
  A(A&&) { std::cout << "Move" << std::endl; }
  std::string s;
};

struct B
{
  A a;
};

int main()
{
  B{A()};
}

Here, I believe struct A is not an aggregate, as it has both non-trivial constructors and also a std::string member which I presume is not an aggregate. This presumably means that B is also not an aggregate.

Yet I can aggregate initialize B. In addition this can be done without either the copy nor move constructor being called (e.g. C++0x GCC 4.5.1 on ideone).

This behavior seems like a useful optimization, particularly for composing together large stack types that don't have cheap moves.

My question is: When is this sort of aggregate initialization valid under C++0x?

Edit + follow up question:

DeadMG below answered with the following:

That's not aggregate initialization at all, it's uniform initialization, which basically in this case means calling the constructor, and the no copy or move is probably done by RVO and NRVO.

Note that when I change B to the following:

struct B
{
  A a;
  B(const A& a_) : a(a_) {}
  B(A&& a_) : a(std::move(a_)) {}
};

A move is performed.

So if this is just uniform initialization and just calling the constructor and doing nothing special, then how do I write a constructor that allows the move to be elided?

Or is GCC just not eliding the move here when it is valid to do so, and if so, is there a compiler and optimization setting that will elide the move?

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

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

发布评论

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

评论(2

我最亲爱的 2024-11-21 09:20:23

根据新标准第 8.5.1 条(聚合),足够简单的类型(例如,没有用户定义的构造函数)有资格作为聚合。对于这样的聚合 Foo,编写 Foo x{a, b, ... }; 将从列表项构造成员。

简单示例:

struct A
{
  std::unordered_map<int, int> a;
  std::string b;
  std::array<int,4> c;
  MyClass d; // Only constructor is MyClass(int, int)
};

// Usage:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, MyClass(4,4)};
// Alternative:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, {4,4}};

对象 x 是通过就地执行的所有相关构造函数来构造的。地图、字符串或 MyClass 不会被复制或移动。请注意,底部的两个变体执行相同的操作。如果您愿意,您甚至可以将 MyClass 的复制和移动构造函数设为私有。

According to the new standard, clause 8.5.1 (Aggretates), a sufficiently simple type (e.g. no user-defined constructors) qualifies as an aggregate. For such an aggregate Foo, writing Foo x{a, b, ... }; will construct the members from the list items.

Simple example:

struct A
{
  std::unordered_map<int, int> a;
  std::string b;
  std::array<int,4> c;
  MyClass d; // Only constructor is MyClass(int, int)
};

// Usage:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, MyClass(4,4)};
// Alternative:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, {4,4}};

The object x is constructed with all the relevant constructors executed in place. No maps or strings or MyClasses ever get copied or moved around. Note that both variants at at the bottom do the same thing. You can even make MyClass's copy and move constructors private if you like.

永不分离 2024-11-21 09:20:23

这根本不是聚合初始化,而是统一初始化,在这种情况下基本上意味着调用构造函数,并且没有复制或移动可能是由 RVO 和 NRVO 完成的。

That's not aggregate initialization at all, it's uniform initialization, which basically in this case means calling the constructor, and the no copy or move is probably done by RVO and NRVO.

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