【问题标题】:Why is a name's point of declaration before its initializer?为什么名称的声明点在其初始值设定项之前?
【发布时间】:2020-10-21 10:06:44
【问题描述】:

说 C++ 标准:

名称的声明点在其完整声明符之后和其之前 初始化程序(如果有)... [basic.scope.pdecl]

也就是说,一个变量在它自己的初始化表达式的上下文中,并且可以被引用。

据我所知,你可以用它做以下类型的事情:

  1. int x = x,格式正确但毫无意义。
  2. void* p = &p,可爱但没用。
  3. std::any a {&a},#2 的 C++17 版本。
  4. MyClass m {std::move(m)},#1 的 C++11 版本,可能是 UB某种方式
  5. MyClass m {myFunc(m)},带有一个获取未初始化对象的函数,我猜它记录在某个地方?并返回一些值,这样构造函数就可以开始了。

#1-4 当然是没用的。似乎可以构建一个接口,其中#5 有意义,但我看不出它是完成任何事情的最直接的方式。由于在评估初始化程序时新变量尚未初始化,因此读取其值是无用/非法的,并且其地址通常对其初始化并不重要。

(可以提出一个稍微更强的案例,将声明点留到初始化程序之后:int avg = avg(a,b,c)。这不是好的代码,它对任何事情都不是必需的,但它会做更多感觉比void* p = &p.)

但这不仅仅是用例。通常,C++ 会努力防止对未初始化对象的访问。例如,它一次设置一个对象的 vtable 一个基类:如果 D 继承自 C 继承自 B,则在 C 的构造函数期间,虚拟方法将被分派到 C 的实现,而不是 D 的实现。可以窥视未初始化对象的常见情况是这种情况,以及(更常见的问题)在成员初始化表达式中使用this

所以我看不到在初始化器之前将名称带入范围的用途,并且我可以看到将其延迟到初始化器之后的明确理由(Stroustrup 也会看到)。鉴于此,C++ 选择的行为是否明确?

【问题讨论】:

  • 我并不是说这是 C 的基本原理,而是int *p = malloc(5 * sizeof(*p));
  • 有趣的问题。我认为标准引用的句子并不仅仅将声明限制为变量。您可以轻松合法地声明一个函数 template <typename T> auto foo() -> decltype(T::foo()); 我不确定这在哪里有用,但它是有效的。
  • int* arr = malloc( 10 * sizeof(*arr) ); 是一个有效的用例。在 Windows API 中,您有时会在结构中存储结构的大小。所以,它确实有它的用例。
  • @AyxanHaqverdili Chris 提到了同样的事情。但是,在 winapi 的情况下,我看到的所有示例代码都使用 sizeof(TYPE),而不是 sizeof(obj)。不是必要的用例,除非需要向后兼容。
  • @Sneftel 你是什么意思它只需要向后兼容?如果您今天正在编写 win32 代码,您仍然会做类似的事情。我喜欢sizeof(obj),因为您不需要重复类型名称。我并不是说规则是好的。我只是说它确实有一些用例。

标签: c++ language-lawyer


【解决方案1】:

它的地址通常不会对其初始化很重要。

template <class T>
struct Node
{
  Node *prev, *next;
  std::optional<T> data;
};

template <class T>
struct List
{
    Node<int> sentinel {&sentinel, &sentinel};
    // methods ...
};

这是一个完全合法且有用的基于标记的双向链表的初始化。

任何类似图的数据结构都可以有自引用,这可以通过将指针或对象的引用作为参数传递给它自己的构造函数来实现。没有理由禁止这些。

如果您担心int x = x; 中固有的未定义行为,只需enable warnings (warning: shameless plug),无论如何您都应该这样做。编译器现在相当擅长捕捉这些东西。

【讨论】:

  • 关于更复杂的自引用的好点。 FWIW,不过,GCC -Wall -Wextra 接受MyClass m{std::move(m)} 没有任何投诉。
猜你喜欢
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
  • 2018-07-16
  • 2021-06-21
  • 1970-01-01
  • 2021-09-02
  • 2019-05-25
  • 1970-01-01
相关资源
最近更新 更多