简体   繁体   English

C++11:赋值运算符是否会阻止类型被 POD 并因此被全局初始化?

[英]C++11: Does an assignment operator prevent a type from being POD, and thus being global-initialized?

Background: I'm in a large-code environment where the undefined order in which global constructors are run is problematic.背景:我在一个大代码环境中,其中运行全局构造函数的未定义顺序是有问题的。 So I have a custom class that is designed to delay initialization until first-use.所以我有一个自定义类,旨在将初始化延迟到第一次使用。 All its magic occurs inside its operator* and operator-> functions;它所有的魔法都发生在它的 operator* 和 operator-> 函数中; they're the only thing defined.它们是唯一定义的东西。 It also stores some state within itself, to make available to the automatic-initialization function.它还在自身内部存储一些状态,以供自动初始化功能使用。 That state must, of course, be POD, so that the whole class is POD, so that it can be completely set up before anyone's code starts running, so that all code everywhere can use all globals everywhere, without fear that the globals haven't been set up yet.那个状态当然必须是POD,这样整个类都是POD,这样它就可以在任何人的代码开始运行之前完全设置好,这样到处的所有代码都可以到处使用所有的全局变量,而不必担心全局变量没有'还没有设置。

A while back someone added a private, never-defined assignment operator, so that the type would never be assigned to (it's not designed to ever change anyway).不久前,有人添加了一个私有的、从未定义的赋值运算符,因此该类型永远不会被赋值(无论如何它都不会被设计为永远改变)。 Now someone else is saying the class is broken because it's not POD.现在有人说这个类坏了,因为它不是 POD。 If instead of it being declared-but-not-defined, I declare it as "=delete", I'm thinking that's somehow better.如果不是声明但未定义,而是将其声明为“=delete”,我认为这样会更好。 And indeed, with that change, std::is_pod<>::value returns true for the type.事实上,随着这种变化, std::is_pod<>​​::value 为该类型返回 true 。

But does as assignment operator prevent a type from being POD?但是 as 赋值运算符会阻止类型成为 POD 吗? I thought the requirements were just that it had to have only public data members, no virtual methods, and no constructor or destructor.我认为要求只是它必须只有公共数据成员,没有虚方法,也没有构造函数或析构函数。

And more to the point for my situation: does the presence of a never-defined assignment operator prevent the class from being able to be initialized at global initialization time, along with all the other global PODs?更重要的是,对于我的情况:从未定义的赋值运算符的存在是否会阻止类在全局初始化时与所有其他全局 POD 一起被初始化?

Reduced example:简化示例:

struct LazyString {
  const char *c_str;

  bool has_been_inited;
  string *lazy_str_do_not_use_directly;

  string &operator*() { return *get(); }
  string *operator->() { return get(); }

 private:
  string *get() {
    // The real code uses a mutex, of course, to be thread-safe.
    if (!has_been_inited) {
      lazy_str_do_not_use_directly = new string(c_str);
      has_been_inited = true;
    }
    return lazy_str_do_not_use_directly;
  }

  // Does this make the class non-POD?
  // If so, does that mean that global variables of this type
  // will not be initialized at global-initialization time, that wonderful
  // moment in time where no code has yet been run?
  void operator=(const LazyString&);

  // If I do this instead, it breaks C++03 compatibility, but is this somehow better?
  void operator=(const LazyString&) = delete;
};

LazyString lazy = { "lazy" };

int main(int argc, char *argv[]) {
  std::cout << *lazy;
}

Does an assignment operator prevent a type from being POD赋值运算符是否会阻止类型成为 POD

Yes.是的。 A POD type must be trivial ; POD 类型必须是平凡的 and so must be trivially copyable ;因此必须是可简单复制的 and so must have no non-trivial copy or move assignment operators.因此必须没有非平凡的复制或移动赋值运算符。

Any user-provided operator is non-trivial, so declaring the copy constructor makes the class non-trivial, and hence non-POD.任何用户提供的运算符都是重要的,因此声明复制构造函数会使类变得重要,因此非 POD。

and thus being global-initialized?从而被全局初始化?

No. Any instantiable type, POD or not, can be a global variable.不。任何可实例化的类型,无论是否为 POD,都可以是全局变量。

UPDATE : From the comment, you meant to ask:更新:从评论中,你的意思是问:

Can it be statically, rather than dynamically, initialised?它可以静态初始化,而不是动态初始化吗?

Yes, since it has a trivial constructor;是的,因为它有一个简单的构造函数; as long as the initialiser is a constant expression.只要初始化器是一个常量表达式。 In your example, { "lazy" } is a constant expression, so LazyString can be statically initialised.在您的示例中, { "lazy" }是一个常量表达式,因此可以静态初始化LazyString

The important feature here is that it has a trivial constructor, not that it's POD.这里的重要特性是它有一个简单的构造函数,而不是它的 POD。 POD means it also meets various other requirements, not relevant to initialisation. POD 意味着它还满足各种其他要求,与初始化无关。

C++ has several stages of initialization for non-local variables with static storage duration (global variable fall into this category) - regardless of whether the type is a POD or not.对于具有静态存储持续时间的非局部变量(全局变量属于这一类),C++ 有几个初始化阶段——无论类型是否为 POD。

  • zero initialization takes place before any other initialization零初始化发生在任何其他初始化之前
  • constant initialization takes place持续初始化
  • dynamic initialization动态初始化

The first two types of initialization must take place before dynamic initialization.前两种类型的初始化必须在动态初始化之前进行。 Dynamic initialization is the situation where the order of initialization can be difficult to set.动态初始化是初始化顺序很难设置的情况。 Some dynamic initialization is unordered, some is ordered within a translation unit, etc.一些动态初始化是无序的,一些是在翻译单元内有序的,等等。

Even if you global variable is not POD, you can be sure that zero initialization will have taken place before any dynamic init.即使您的全局变量不是 POD,您也可以确保在任何动态初始化之前已经进行了零初始化。

See C++11 3.6.2 "Initialization of non-local variables" for details.有关详细信息,请参阅 C++11 3.6.2“非局部变量的初始化”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM