草庐IT

c++ - C++11 中的数组声明和初始化

coder 2023-11-12 原文

这里有 8 种在 C++11 中声明和初始化数组的方法,在 g++ 下看起来没问题:

/*0*/ std::array<int, 3> arr0({1, 2, 3});
/*1*/ std::array<int, 3> arr1({{1, 2, 3}});
/*2*/ std::array<int, 3> arr2{1, 2, 3};
/*3*/ std::array<int, 3> arr3{{1, 2, 3}};
/*4*/ std::array<int, 3> arr4 = {1, 2, 3};
/*5*/ std::array<int, 3> arr5 = {{1, 2, 3}};
/*6*/ std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
/*7*/ std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});

根据严格的标准(以及即将推出的 C++14 标准),正确的标准是什么?
什么是最常见/最常用的和那些要避免的(以及出于什么原因)?

最佳答案

C++11 总结/TL;DR

  • 由于支架省略缺陷,示例 0、2、6 不需要工作。然而,最新版本的编译器实现了针对该缺陷的建议解决方案,因此这些示例将起作用。
  • 由于未指明是否std::array包含一个原始数组。因此,示例 1、3、5、7 不需要工作。但是,我不知道它们不起作用的标准库实现(在实践中)。
  • 示例 4 将始终有效:std::array<int, 3> arr4 = {1, 2, 3};

  • 我更喜欢版本 4 或版本 2(带有括号省略修复),因为它们直接初始化并且需要/可能工作。

    对于 Sutter 的 AAA 风格,您可以使用 auto arrAAA = std::array<int, 3>{1, 2, 3}; ,但这需要括号省略修复。
    std::array需要是一个聚合 [array.overview]/2,这意味着它没有用户提供的构造函数(即只有默认、复制、移动构造函数)。
    std::array<int, 3> arr0({1, 2, 3});
    std::array<int, 3> arr1({{1, 2, 3}});
    

    使用 (..) 初始化是直接初始化。这需要构造函数调用。在arr0的情况下和 arr1 ,只有复制/移动构造函数是可行的。因此,这两个示例意味着创建一个临时 std::array从支撑初始化列表中,并将其复制/移动到目的地。通过复制/移动省略,编译器可以省略该复制/移动操作,即使它有副作用。

    注意即使临时对象是纯右值,它也可能调用一个拷贝(语义上,在复制省略之前)作为 std::array 的移动构造函数。可能不会被隐式声明,例如如果它被删除了。
    std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
    std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
    

    这些是复制初始化的示例。创建了两个临时对象:
  • 通过支撑初始化列表 {1, 2, 3}调用复制/移动构造函数
  • 通过表达式 std::array<int, 3>(..)

  • 然后将后者临时复制/移动到命名的目标变量。可以省略两个临时对象的创建。

    据我所知,一个实现可以写一个 explicit array(array const&) = default;构造器且不违反标准;这将使这些示例格式错误。 ([container.requirements.general] 排除了这种可能性,感谢 David Krauss,参见 this discussion。)
    std::array<int, 3> arr2{1, 2, 3};
    std::array<int, 3> arr3{{1, 2, 3}};
    std::array<int, 3> arr4 = {1, 2, 3};
    std::array<int, 3> arr5 = {{1, 2, 3}};
    

    这是聚合初始化。它们都“直接”初始化 std::array , 不调用 std::array 的构造函数并且没有(语义上)创建临时数组。 std::array成员(member)通过复制初始化进行初始化(见下文)。

    关于大括号省略的主题:

    在 C++11 标准中,大括号省略仅适用于形式 T x = { a }; 的声明。但不是到 T x { a }; .这是 considered a defect并将在 C++1y 中修复,但是建议的解决方案不是标准的一部分(DRWP 状态,请参阅链接页面的顶部),因此您不能指望您的编译器也为 T x { a }; 实现它。 .

    因此,std::array<int, 3> arr2{1, 2, 3}; (示例 0、2、6)严格来说是格式错误的。据我所知,最新版本的 clang++ 和 g++ 允许在 T x { a }; 中省略括号。已经。

    在示例 6 中,std::array<int, 3>({1, 2, 3})使用复制初始化:参数传递的初始化也是复制初始化。然而,大括号省略的缺陷限制“在形式 T x = { a }; 的声明中”也不允许参数传递的大括号省略,因为它不是声明,当然也不是那种形式。

    关于聚合初始化的话题:

    Johannes Schaub指出in a comment ,只保证可以初始化一个 std::array使用以下语法 [array.overview]/2:
    array<T, N> a = { initializer-list };

    You can deduce from that, if brace-elision is allowed in the form T x { a };, that the syntax

    array<T, N> a { initializer-list };

    is well-formed and has the same meaning. However, it is not guaranteed that std::array actually contains a raw array as its only data member (also see LWG 2310). I think one example could be a partial specialization std::array<T, 2>, where there are two data members T m0 and T m1. Therefore, one cannot conclude that

    array<T, N> a {{ initializer-list }};

    is well-formed. This unfortunately leads to the situation that there's no guaranteed way of initializing a std::array temporary w/o brace elision for T x { a };, and also means that the odd examples (1, 3, 5, 7) are not required to work.


    All of these ways to initialize a std::array eventually lead to aggregate-initialization. It is defined as copy-initialization of the aggregate members. However, copy-initialization using a braced-init-list can still directly initialize an aggregate member. For example:

    struct foo { foo(int); foo(foo const&)=delete; };
    std::array<foo, 2> arr0 = {1, 2};      // error: deleted copy-ctor
    std::array<foo, 2> arr1 = {{1}, {2}};  // error/ill-formed, cannot initialize a
                                           // possible member array from {1}
                                           // (and too many initializers)
    std::array<foo, 2> arr2 = {{{1}, {2}}}; // not guaranteed to work
    

    第一个尝试从初始化子句 1 初始化数组元素和 2 , 分别。此复制初始化等效于 foo arr0_0 = 1;这又相当于 foo arr0_0 = foo(1);这是非法的(已删除的 copy-ctor)。

    第二个不包含表达式列表,而是一个初始值设定项列表,因此它不满足 [array.overview]/2 的要求。在实践中,std::array包含一个原始数组数据成员,它将(仅)从第一个初始化子句 {1} 初始化,第二条{2}然后是非法的。

    第三个与第二个有相反的问题:如果有数组数据成员它可以工作,但不能保证。

    关于c++ - C++11 中的数组声明和初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20519992/

    有关c++ - C++11 中的数组声明和初始化的更多相关文章

    1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    2. ruby - 其他文件中的 Rake 任务 - 2

      我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

    3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

      Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

    5. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

      我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

    6. ruby-on-rails - 未初始化的常量 Psych::Syck (NameError) - 2

      在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到ruby​​gems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决

    7. ruby - 多次弹出/移动 ruby​​ 数组 - 2

      我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

    8. ruby - 将数组的内容转换为 int - 2

      我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

    9. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

      我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

    10. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

      我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

    随机推荐