问题标签 [one-definition-rule]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
1993 浏览

c++ - 类方法的显式特化 - 符号已定义

单一定义规则规定程序应该包含每个非内联函数的一个定义。对于模板类的成员,这对我来说并不完全清楚:

在这种情况下,clientX.obj 和 clientY.obj 都有一个 .obj 的定义Foo<int>::foo。链接器抱怨这个符号被定义了不止一次:

当我inline添加 的定义时Foo<int>::foo(),一切顺利,链接器很高兴。此外,当我在单独的编译单元(例如 intfoo.cpp)中定义它们时。

(注意:此解决方案在https://stackoverflow.com/a/1481796/6610中提出)

可能是一个误解,但模板类的成员函数不是总是“内联”的吗?这里的规则是什么?

0 投票
3 回答
2105 浏览

c++ - constexpr 和 ODR

如果我们有一个widget.hpp包含以下内容的头文件:

...我们有两个翻译单元是从两个只包含的源文件生成的,widget.hpp这是否违反了一个定义规则(更具体地说,使用foo违反了一个定义规则)?

foo具有内部链接,但它也是一个常量表达式。根据我对 C++11 标准中的 3.2.6 的阅读(我将在下面引用),如果要求 #2 不仅仅指静态数据成员,则这是格式良好的。


3.2.6 要求#2:

在 D 的每个定义中,根据 3.4 查找的相应名称应指在 D 的定义中定义的实体,或应指同一实体,经过重载解析(13.3)和部分模板特化匹配(14.8) .3),除了如果对象在 D 的所有定义中具有相同的文字类型,并且该对象使用常量表达式 (5.19) 初始化,则名称可以引用具有内部链接或没有链接的非易失性 const 对象,并且该对象不是 ODR 使用的,并且该对象在 D 的所有定义中具有相同的值

0 投票
2 回答
3804 浏览

c++ - 头文件中定义的非内联虚函数

单一定义规则规定:
在整个程序中,一个对象或非内联函数不能有多个定义。(来自维基百科)

好吧,我知道如果在头文件中定义了一个成员函数,它就会被隐式内联,并且可以使用 ODR。

但是虚函数呢?我们知道,如果一个虚函数被多态调用,它就不能被内联。如果在头文件中定义了这样的虚函数,那会违反 ODR 吗?

例如:

我很好奇:

vfunc(and dtor) 在 foo.cpp 和 main.cpp 中都被多态调用(不是内联),这意味着它在整个程序中定义了两次,所以它违反了 ODR,不是吗?它是如何编译的(链接)?

我刚刚看到:

不止一个定义

在某些情况下,可以有多个类型或模板的定义。由多个头文件和源文件组成的程序通常具有多个类型的定义,但每个翻译单元不超过一个定义。如果一个程序包含多个类型的定义,那么每个定义必须是等价的(也取自维基百科)

是什么certain cases?上述情况是否属于其中之一?

0 投票
6 回答
12188 浏览

c - C 不同文件中定义的同一个全局变量

我正在阅读这里的代码(中文)。有一段代码是关于在 C 中测试全局变量的。该变量已在包含两次a的文件中定义。t.h在文件中foo.c定义了struct b一些值和一个main函数。在main.c文件中,定义了两个未初始化的变量。

使用 Ubuntu GCC 4.4.3 编译后,结果如下:

变量ab两个函数中的地址相同,但大小发生b了变化。我无法理解它是如何工作的!

0 投票
2 回答
1073 浏览

c++ - 为什么静态成员的类内初始化会违反 ODR?

Stack Overflow 上有几个问题,类似于“为什么我不能在 C++ 中初始化静态数据成员”。大多数答案都引用标准告诉您可以做什么那些试图回答为什么通常指向一个链接(现在看似不可用)的人 [编辑:实际上它是可用的,见下文] 在 Stroustrup 的网站上,他指出允许静态成员的类内初始化将违反单一定义规则(ODR )。

然而,这些答案似乎过于简单。编译器完全能够在需要时解决 ODR 问题。例如,考虑 C++ 标头中的以下内容:

如果我在多个翻译单元中进行实例化,编译器/链接器的魔法就会发挥作用,并且我会在最终的可执行文件中TemplateExample<0>获得一份副本。TemplateExample<0>::str

所以我的问题是,考虑到编译器显然可以解决模板类的静态成员的 ODR 问题,为什么它不能对非模板类也这样做呢?

编辑:Stroustrup 常见问题解答可在此处获得。相关语句是:

但是,为了避免复杂的链接器规则,C++ 要求每个对象都有唯一的定义。如果 C++ 允许对需要作为对象存储在内存中的实体进行类内定义,则该规则将被打破

然而,那些“复杂的链接器规则”似乎确实存在并且在模板案例中使用,那么为什么不在简单案例中呢?

0 投票
2 回答
19058 浏览

c++ - “使用 ODR” 是什么意思?

这只是在另一个问题的背景下提出的。

显然,类模板中的成员函数只有在使用 ODR 时才会被实例化。有人可以解释这到底是什么意思。关于单一定义规则(ODR)的维基百科文章没有提到“ ODR-use ”。

但是标准将其定义为

名称显示为潜在求值表达式的变量是odr-used的,除非它是一个满足出现在常量表达式 (5.19) 中的要求并且立即应用左值到右值转换 (4.1) 的对象。

在 [basic.def.odr] 中。

编辑:显然这是错误的部分,整个段落包含不同事物的多个定义。这可能与类模板成员函数相关:

名称显示为潜在求值表达式或一组候选函数的成员的非重载函数,如果在从潜在求值表达式中引用时通过重载决议选择,则为 odr-used,除非它是纯虚函数函数及其名称没有明确限定。

但是我不明白,这条规则如何在多个编译单元中起作用?如果我显式实例化类模板,是否所有成员函数都实例化了?

0 投票
1 回答
148 浏览

c++ - 默认模板参数是否进入单一定义规则?

多个翻译单元是否可以声明具有不同默认模板参数但定义相同的相同模板?例如,如果b.cppc.cpp中的翻译单元链接在一起,以下代码是否违反 ODR?

0 投票
1 回答
411 浏览

c++ - 内联函数:访问冲突读取位置 0xcdcdcdd5?

我遇到了一个奇怪的问题,我曾经在运行时收到异常消息:
Unhandled exception at 0x0137d451 in I2cTlmTest.exe: 0xC0000005: Access violation reading location 0xcdcdcdd5.

我在创建对象“C”期间收到此消息。我已经对其进行了调试,但无法做太多事情,因为一旦调试到达class 函数中this的断点,(指针)变量(和指针)的值就会设置为 (0xcdcdcdcd) 。我环顾四周寻找可能的罪魁祸首,认为变量可能未初始化或可能在我到达函数之前被删除。但是在函数中,当我进入函数并设置为魔法值时,所有变量都被初始化并消失。B::getHelperBA::getHelperB::getHelper

经过一番调试后,我只是将默认内联A::getHelper移至 A.cpp。令我惊讶的是,我的应用程序开始运行。我已经解决了我的问题,但不知道为什么 inline 函数A会导致问题。非常感谢任何帮助。很抱歉这个问题很长,但没有其他选择。

我尝试使用以下代码片段创建一个类似的场景:

0 投票
3 回答
3601 浏览

c++ - 全局 std::string 和一个定义规则

我有一个包含以下定义的头文件

现在我将此文件包含在两个不同的翻译单元中并编译源代码。一切正常,但为什么呢?这有望打破one definition rule

现在更有趣的是,我正在改变类型

这就是预期的错误

它的工作方式与 std::string for intcharshort其他整数类型的工作方式相同。这是什么?

0 投票
1 回答
1144 浏览

c++ - constexpr 全局类类型

我的理解是constexpr类类型的全局变量几乎无法使用,因为

  • 这样的对象必须在每个 TU 中定义,因为constexpr不允许对象的前向声明。

  • 默认链接static会导致在内联函数中命名对象(使用或不使用 ODR)违反 ODR,因为各自的inline定义将具有不同的含义。

  • 如果对象是 ODR 使用的,那么每个 TU 具有一个定义的声明extern constexpr将违反 ODR 规则,这发生在对其进行引用时。

    • 对隐式this参数进行引用,即使成员函数未使用它。
    • 如果您尝试通过引用传递对象,显然会发生。
    • 如果您尝试按值传递对象,也会发生这种情况,这会隐式使用复制或移动构造函数,根据定义,该构造函数通过引用传递。
    • 如果声明了一个对象,extern constexpr即使没有使用 ODR,GCC 和 Clang 都会抱怨 ODR 违规(多个定义)。

这一切都正确吗?有没有办法在constexpr不将其包装在函数中的情况下拥有一个全局类类型inline