繁体   English   中英

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

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

背景:我在一个大代码环境中,其中运行全局构造函数的未定义顺序是有问题的。 所以我有一个自定义类,旨在将初始化延迟到第一次使用。 它所有的魔法都发生在它的 operator* 和 operator-> 函数中; 它们是唯一定义的东西。 它还在自身内部存储一些状态,以供自动初始化功能使用。 那个状态当然必须是POD,这样整个类都是POD,这样它就可以在任何人的代码开始运行之前完全设置好,这样到处的所有代码都可以到处使用所有的全局变量,而不必担心全局变量没有'还没有设置。

不久前,有人添加了一个私有的、从未定义的赋值运算符,因此该类型永远不会被赋值(无论如何它都不会被设计为永远改变)。 现在有人说这个类坏了,因为它不是 POD。 如果不是声明但未定义,而是将其声明为“=delete”,我认为这样会更好。 事实上,随着这种变化, std::is_pod<>​​::value 为该类型返回 true 。

但是 as 赋值运算符会阻止类型成为 POD 吗? 我认为要求只是它必须只有公共数据成员,没有虚方法,也没有构造函数或析构函数。

更重要的是,对于我的情况:从未定义的赋值运算符的存在是否会阻止类在全局初始化时与所有其他全局 POD 一起被初始化?

简化示例:

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

赋值运算符是否会阻止类型成为 POD

是的。 POD 类型必须是平凡的 因此必须是可简单复制的 因此必须没有非平凡的复制或移动赋值运算符。

任何用户提供的运算符都是重要的,因此声明复制构造函数会使类变得重要,因此非 POD。

从而被全局初始化?

不。任何可实例化的类型,无论是否为 POD,都可以是全局变量。

更新:从评论中,你的意思是问:

它可以静态初始化,而不是动态初始化吗?

是的,因为它有一个简单的构造函数; 只要初始化器是一个常量表达式。 在您的示例中, { "lazy" }是一个常量表达式,因此可以静态初始化LazyString

这里的重要特性是它有一个简单的构造函数,而不是它的 POD。 POD 意味着它还满足各种其他要求,与初始化无关。

对于具有静态存储持续时间的非局部变量(全局变量属于这一类),C++ 有几个初始化阶段——无论类型是否为 POD。

  • 零初始化发生在任何其他初始化之前
  • 持续初始化
  • 动态初始化

前两种类型的初始化必须在动态初始化之前进行。 动态初始化是初始化顺序很难设置的情况。 一些动态初始化是无序的,一些是在翻译单元内有序的,等等。

即使您的全局变量不是 POD,您也可以确保在任何动态初始化之前已经进行了零初始化。

有关详细信息,请参阅 C++11 3.6.2“非局部变量的初始化”。

暂无
暂无

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

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