问题标签 [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.
c++ - 关于 ODR、声明和定义的一些问题
对不起,如果问题是旧的或有点愚蠢。
我知道声明和定义的基础知识,但在 C++ 中似乎有很多不一致或“例外”,这使得它不和谐,至少对我来说是这样。或者,我误解了什么。
所以,在头文件中,我们声明了一些变量并定义了类类型(也听说过“类声明”,不知道哪个更准确);在每个类中,我们声明成员变量和函数。然后在一些 .cc/.cpp 文件中,我们只定义成员函数来实现类。如果“不幸”有一个静态成员变量/函数,它被认为是特殊的并且完全独立于关联的类,它必须在类之外定义,作为成员变量中唯一的一种“怪胎”。
当 .cpp 文件#include
sa定义类类型的头文件时(请注意,该头文件中的类类型定义似乎“不完整”,因为它的功能在其他地方定义。),.cpp 文件将类类型定义放在开头,以及其他可能的声明。
在.cpp文件中,#include
d类的静态成员变量已经在实现.cpp中连同成员函数一起定义了,那么如果创建了类的实例,那么非静态的“普通”成员变量呢?假设它是Class A;
,那么非静态成员变量是否会被定义A a;
?当然定义a
了一个类型A
的对象,但是它的非静态成员变量是否也被定义(在分配内存的意义上定义)?如果是这样,那么两个相同类型的对象,比如说和,完全可以在一起,因为和有不同的a1
a2
A
a1.mem_var_1
a2.mem_var_1
关于不同类实例名称的定义?或者,它们共享“相同的定义”但具有不同的值和副本?
成员函数呢?它们已经在类类型的.cpp文件中定义了,但是当我们创建多个实例时,它们不会在.cpp中共享相同的定义但在内存中有不同的副本(我猜是同一个成员函数的多个副本至少对于内部局部变量的不同值是必要的)?静态函数呢?
或者,我误解了一些东西,因为我们程序员“定义”文件中的某些东西不等于编译器和链接器“定义”文件中的东西?定义的真正作用和含义是什么?我们在一个文件中写入“定义”某些东西,但系统可以“定义”不同的东西,至少在秘密制作多个副本和东西的意义上?
我头痛...
c++ - 关于类成员访问表达式的一种定义规则
在 N4296, 3.2 [basic.def.odr]p3 中:
x
名称显示为潜在求值表达式的变量ex
被 odr 使用,ex
除非应用左值到右值转换来x
生成不调用任何非平凡函数的常量表达式,并且如果x
是对象,ex
则它是表达式 的潜在结果集e
,其中应用了左值到右值的转换e
,或者e
是丢弃值表达式。
这一段怎么解释?我找到了两个解释。
1 从这里“试图理解 C++14 (N4140) 中的 [basic.def.odr]/2 ”
让我们把它分成几个步骤:在表达式 `ex` 中出现变量 `x` 构成了 odr-use,除非:
- 要么
ex
没有潜在的评估,要么- 必须满足以下所有条件:
- “应用左值到右值的转换来
x
产生一个不调用任何非平凡函数的常量表达式” 和- “
ex
是表达式的潜在结果集合中的一个元素e
” ,并且以下任一项成立:
- “要么左值到右值的转换应用于
e
”- " or
e
是一个弃值表达式"
和 2 来自 cppreference http://en.cppreference.com/w/cpp/language/definition
除非以下任何一项为真,否则
x
潜在求值表达式中的变量ex
是 odr-used :
应用左值到右值的转换来
x
产生一个不调用非平凡函数的常量表达式
x
是一个对象,而 ex 是较大表达式的潜在结果之一e
,其中较大的表达式要么是丢弃值表达式,要么是左值到右值的转换
关于两个规则的第一个答案是and,另一个是any。哪一个是对的?
请将规则拆分为步骤来解释此代码:
c++ - 静态常量的链接器错误似乎没有被 odr 使用
当您深入了解细节时,标准中的 odr-used 定义非常令人困惑(至少对我来说是这样)。我通常依赖“如果引用”的非正式定义,除非可以进行左值到右值的转换。对于整数常量,它们应该被视为右值,这似乎应该从引用规则中排除。这是我无法链接的示例代码:
我得到的链接器错误:
现场样本:http ://coliru.stacked-crooked.com/a/4d4c27d6b7683fe8
为什么定义是MIN_VALUE
必需的?它只是文字值的常量,编译器应将其优化为std::max(m_otherValue, 5)
. 所以我就是不明白。
c++ - 以下内容是否真的违反了 ODR?
从这里:
此函数违反了 ODR([basic.def.odr] §3.2/6 )两次,因为构造函数 2 参数都没有接收左值到右值的转换。因此它们通过地址传递,但地址取决于 TU,因为 const(和 constexpr)意味着内部链接。
我最初认为它确实如此,但问题是它magic_number
具有内部联系。既然它具有内部链接,那么它是否本质上不会将magic_number
它们视为不同翻译单元中的不同变量,因此不视为同一变量的多个定义?有人可以通过引用 C++ 标准的最新工作草案来指定这一点吗?
ios - iOS9 按需资源 (ODR) 的向后兼容性
按需资源 (iOS)
按需资源是您可以使用关键字标记并按标记分组请求的资源(例如图像和声音)。App Store 在 Apple 服务器上托管资源并为您管理下载。按需资源可实现更快的下载速度和更小的应用程序大小,从而改善首次启动体验。例如,游戏应用程序可能会将资源划分为游戏关卡,并仅在应用程序预期用户将移动到该级别时才请求下一个级别的资源。同样,只有当用户购买了相应的应用内购买时,应用才能请求应用内购买资源。
ODR 对某些应用程序很有用,但这个新功能的向后兼容机制是什么。老实说,一个应用程序只支持最新的 iOS 版本是非常罕见的。它总是最多返回 2 个版本。
我的理论是,也许旧版本会简单地忽略整个 ODR,让用户从商店下载完整的应用程序包。
有没有人有更多的信息可以澄清这一点?
c++ - 有没有办法检测内联函数 ODR 违规?
所以我在 2 个独立的翻译单元中有这段代码:
正常编译时,结果为10
. 当使用 -O3(内联)编译时,我得到11
.
我显然违反了func()
.
当我开始将不同 dll 的源合并到更少的 dll 中时,它就出现了。
我努力了:
- GCC 5.1
-Wodr
(需要-flto
) - 黄金链接器
-detect-odr-violations
ASAN_OPTIONS=detect_odr_violation=1
在使用地址清理程序运行检测的二进制文件之前进行设置。
据推测,Asan 可以捕获其他 ODR 违规行为(具有不同类型的全局变量或类似的东西......)
这是一个非常讨厌的 C++ 问题,我很惊讶没有可靠的工具来检测它。
也许我误用了我尝试过的工具之一?或者有什么不同的工具可以做到这一点?
编辑:
即使我做了两个func()
完全不同的实现,这个问题仍然没有被注意到,所以它们不会被编译成相同数量的指令。
这也会影响在类体内定义的类方法——它们是隐式内联的。
之后有大量复制/粘贴 + 小修改的遗留代码是一种乐趣。
c++ - 传递静态 constexpr 成员而没有按值定义的奇怪行为
我惊讶地发现,当没有类外定义时,GCC 和 Clang 在按值传递静态 constexpr 成员时是否给我一个链接器错误意见不一:
片段可以在这里播放。
我想使用没有类外定义的第一行语法:
当 中没有成员时E
,Clang 和 GCC 似乎只关心我是否对nested
ODR 跳闸没有课外定义(例如,通过获取地址)。这个标准是强制性的还是运气?
当有成员时,GCC(5.2)似乎还希望我手动定义一个 constexpr 复制构造函数。这是一个错误吗?
从谷歌搜索和 SO 我发现了几个不同的答案,但很难区分哪些是最新的 C++14。在 C++98/03 中,我相信只能在类中初始化整数类型。我认为C++14 将其扩展为“文字”类型,其中包括 constexpr 可构造的东西。我不知道这是否与说我可以在没有课外定义的情况下逍遥法外是一样的。
ios9 - 按需资源 (iOS9) 问题
我计划在我的应用程序中使用新的(iOS9)功能“按需资源”,以减少整体大小。一切运行良好,但是当我使用 Testflight 测试我的应用程序时,我看到应该仅按需下载的资产数量(大约 30mb)反而在安装时下载,并且被 iOS 视为“文档和数据”。
所以我的应用程序应该是大约 95 mb,而不是超过 125Mb(95 mb + 30 mb(“文档和数据”))。有什么建议么?有人观察过同样的问题吗?
c++ - 我能保证不会被这种 ODR 违规行为所困扰吗?
我有一个头文件,它声明了一个带有静态变量的模板并定义了它:
此标头包含在main.cpp
共享库和共享库mylib
中。特别是,mylib_baz.hpp
只包含这个模板并声明一个修改模板特化的函数。
和
当我制作mylib.so
(包含mylib_baz.o
)时,符号 forfoo<123>::bar
存在并声明为弱。但是,在 my 中,符号 forfoo<123>::bar
也被声明为弱main.o
:
看来我违反了一个定义规则(foo<123>::bar
在my_header.cpp
和中定义main.cpp
)。但是,对于 g++ 和 clang,符号都被声明为弱(或唯一),所以我不会被这个所困扰——所有访问都是为了foo<123>::bar
修改同一个对象。
问题 1:这是一个巧合(也许 ODR 对模板的静态成员的工作方式不同?)还是我实际上通过标准保证了这种行为?
问题 2:我怎么能预测我观察到的行为?也就是说,究竟是什么让编译器声明符号为弱?
c++ - C++ 对一个定义规则的混淆
我正在阅读有关One Definition Rule的内容。它说:
如果一个 .cpp 文件定义了struct S { int x; }; 另一个 .cpp 文件定义了struct S { int y; }; ,将它们链接在一起的程序的行为是未定义的。这通常通过未命名的命名空间来解决。
我不明白为什么以及它是如何未定义的?有人能解释一下这背后的真正原因吗?未命名的命名空间如何解决?