【问题标题】:Why doesn't #pragma once guard against multiple non-constexpr definitions?为什么#pragma once 不防范多个非 constexpr 定义?
【发布时间】:2020-01-17 20:14:24
【问题描述】:

刚刚花了一段时间调试一个多重定义错误,但我不清楚为什么会发生这种行为并希望了解。

我在头文件中有类似的内容。

//foo.h
#pragma once

my_states States[N] = {...};

后来,bar.h 包含了foo.h,因为bar.cpp 具有需要了解my_states 的功能。

当我为bar 编写单元测试并将bar.h 包含在test.cpp 中时,问题就出现了。

bar.o: multiple definition of MyNamespace::named_states
test.o: first defined here

我已通过更改为

解决了这个问题

constexpr my_states States[n] = {...};foo.h

但是我不明白为什么这解决了这个问题。我知道我对符号 my_states 有多个定义,这使链接器感到困惑,但是如果我有我的 #pragma once 保护,为什么要多次定义它?我不确定为什么我需要 constexpr 限定符来表示这应该只有 1 个定义,而据我所知 #pragma once 应该阻止编译器首先尝试创建多个定义。

【问题讨论】:

  • pragma 一旦阻止为 one 编译单元重新包含相同的头文件,它就不能跨编译单元工作。
  • 这应该分成 2 个独立的问题 - 一个是关于为什么 constexpr 解决了这个问题,一个是关于为什么 #pragma once 没有。

标签: c++ gcc c++14


【解决方案1】:

#pragma once 只保证头文件只包含一次,它不处理代码。

关于my_states 的第二个问题 - 如果没有constexpr,您尝试定义一个可以在运行时修改的全局变量(或类似的东西)。通过在头文件中设置其状态,您实际上使包含此头文件的每个库都实例化并包含变量,而它应该是唯一定义的……基本上它是一团糟,无法编译。您可以在头文件中声明静态/全局变量,但您应该在单个 cpp 文件中实例化它们。

通过将constexpr 添加到您向编译器传达的变量声明中,它不能在运行时修改,而且它的值在编译时是已知的。所以不用担心哪个库存储/实例化它或任何类似的东西,因为它是编译时已知的绝对常量。

【讨论】:

  • 谢谢,这是有道理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-12
  • 1970-01-01
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
相关资源
最近更新 更多