草庐IT

c++ - union 体的活跃成员,统一的初始化和构造函数

coder 2024-02-05 原文

作为(Working Draft of) C++ Standard说:

9.5.1 [class.union]

In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [...] The size of a union is sufficient to contain the largest of its non-static data members. Each non-static data member is allocated as if it were the sole member of a struct. All non-static data members of a union object have the same address.

但我不知道如何确定哪个是 union 的活跃成员,而且我还没有足够的时间深入研究标准来找到标准对它的描述,我试图弄清楚活跃的成员是如何成员已设置,但我发现它是如何交换的:

9.5.4 [class.union]

[ Note: In general, one must use explicit destructor calls and placement new operators to change the active member of a union. —end note ] [Example: Consider an object u of a union type U having non-static data members m of type M and n of type N. If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m to n using the destructor and placement new operator as follows:

u.m.~M();
new (&u.n) N;

end example ]

所以我的猜测是 union 的活跃成员是第一个被分配、使用、构建或安置新的;但这对于统一初始化变得有点棘手,请考虑以下代码:

union Foo
{
    struct {char a,b,c,d;};
    char array[4];
    int integer;
};

Foo f; // default ctor
std::cout << f.a << f.b << f.c << f.d << '\n';

上面代码中哪个是 union 的活跃成员? std::cout 是从联盟的活跃成员那里读取的吗?下面的代码呢?

Foo f{0,1,2,3}; // uniform initialization
std::cout << f.a << f.b << f.c << f.d << '\n';

通过上面的代码,我们可以初始化嵌套的匿名结构或数组,如果我只提供一个整数,我可以初始化 Foo::aFoo::arrayFoo::integer...哪个是活跃成员?

Foo f{0}; // uniform initialization
std::cout << f.integer << '\n';

我猜活跃成员在上述所有情况下都是匿名结构,但我不确定。

如果我想激活一个或另一个 union 成员,我应该提供一个构造函数来激活它吗?

union Bar
{
    // #1 Activate anonymous struct
    Bar(char x, char y, char z, char t) : a(x),b(y),c(z),d(t) {}
    // #2 Activate array
    Bar(char (&a)[4]) { std::copy(std::begin(a), std::end(a), std::begin(array)); }
    // #3 Activate integer
    Bar(int i) : integer(i) {}

    struct {char a,b,c,d;};
    char array[4];
    int integer;
};

我几乎可以肯定 #1 和 #3 会将匿名结构和整数标记为事件 union ,但我不知道 #2 因为在我们到达构造函数主体的那一刻,成员已经建!那么我们是不是在不活跃的 union 成员上调用 std::copy

问题:

  • 如果 Foo 是用以下统一初始化构造的,哪些是事件 union 成员:
    • Foo{};
    • Foo{1,2,3,4};
    • Foo{1};
  • Bar 的 #2 构造函数中,Bar::array 是活跃的 union 成员?
  • 我可以在标准中的哪个位置了解到哪个是活跃的 union 成员以及如何在不放置新成员的情况下对其进行设置?

最佳答案

您对缺乏对 union 活跃成员的严格定义的担忧得到了标准化委员会(至少部分)成员的认同 - 请参阅最新说明(日期为 2015 年 5 月) ) 在 active issue 1116 的描述中:

We never say what the active member of a union is, how it can be changed, and so on. [...]

我认为我们可以期待在工作草案的 future 版本中进行某种澄清。该注释还表明,我们迄今为止最好的是您在问题 [9.5p4] 中引用的段落中的注释。

话虽如此,让我们看看您的其他问题。

首先,标准C++中没有匿名结构(只有匿名 union ); struct {char a,b,c,d;}; 如果编译时使用相当严格的选项 (-std=c++1z -Wall -Wextra -pedantic 会给你警告> 例如,用于 Clang 和 GCC)。展望 future ,我假设我们有一个像 struct { char a, b, c, d; 这样的声明。 } s; 并且其他所有内容都相应地进行了调整。

第一个示例中隐式默认的默认构造函数不根据 [12.6.2p9.2] 执行任何初始化:

In a non-delegating constructor, if a given potentially constructed subobject is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then

(9.1) - if the entity is a non-static data member that has a brace-or-equal-initializer and either

(9.1.1) - the constructor’s class is a union (9.5), and no other variant member of that union is designated by a mem-initializer-id or
(9.1.2) - the constructor’s class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by a mem-initializer-id,

实体按照 8.5 中的规定进行初始化;

(9.2) - 否则,如果实体是匿名 union 体或变体成员 (9.5),则不执行初始化;

(9.3) - 否则,实体默认初始化 (8.5)。

我想我们可以说 f 在其默认构造函数完成执行后没有事件成员,但我不知道有任何标准措辞可以清楚地表明这一点。实际上可以说,尝试读取任何 f 成员的值是没有意义的,因为它们是不确定的。

在您的下一个示例中,您使用的是聚合初始化,根据 [8.5.1p16],它是为 union 合理定义的:

When a union is initialized with a brace-enclosed initializer, the braces shall only contain an initializer-clause for the first non-static data member of the union. [ Example:

union u { int a; const char* b; }; 
u a = { 1 }; 
u b = a; 
u c = 1;               // error 
u d = { 0, "asdf" };   // error 
u e = { "asdf" };      // error 

end example ]

这与 [8.5.1p12] 中指定的用于初始化嵌套结构的大括号省略一起使结构成为事件成员。它也回答了您的下一个问题:您只能使用该语法初始化第一个 union 成员。

你的下一个问题:

If I want to activate one or the other union member, should I provide a constructor activating it?

是的,或者根据上面引用的 [12.6.2p9.1.1] 为一个成员使用 brace-or-equal-initializer;像这样:

union Foo
{
    struct { char a, b, c, d; } s;
    char array[4];
    int integer = 7;
};

Foo f;

在上面之后,事件成员将是 integer。以上所有内容也应该回答您关于 #2 的问题(当我们到达构造函数的主体时,成员尚未构造 - #2 也可以)。

最后,Foo{}Foo{1} 都执行聚合初始化;它们分别被解释为 Foo{{}}Foo{{1}}(因为大括号省略),并初始化结构;根据 [ 8.5.1p7].


所有标准引述均来自当前工作草案,N4527 .


论文N4430 ,其中处理了一些相关的问题,但尚未集成到工作草案中,为活跃成员提供了定义:

In a union, a non-static data member is active if its name refers to an object whose lifetime has begun and has not ended ([basic.life]).

这有效地将责任推给了 [3.8] 中生命周期的定义,它也有一些针对它的问题,包括前面提到的 issue 1116。 ,所以我认为我们必须等待几个这样的问题得到解决才能有一个完整和一致的定义。目前的生命周期定义似乎还没有完全准备好。

关于c++ - union 体的活跃成员,统一的初始化和构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31388208/

有关c++ - union 体的活跃成员,统一的初始化和构造函数的更多相关文章

  1. 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”因此,为了解决

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  5. ruby-on-rails - 未在 Ruby 中初始化的对象 - 2

    我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调

  6. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  8. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  9. ruby-on-rails - ActionController::RoutingError: 未初始化常量 Api::V1::ApiController - 2

    我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc

  10. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

随机推荐