- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
Stack Overflow 上有几个问题,类似于“为什么我不能在 C++ 中初始化静态数据成员”。大多数答案都引用标准告诉你什么你可以做什么;那些试图回答为什么的人通常指向一个链接(现在似乎不可用)[编辑:实际上它是可用的,见下文]在 Stroustrup 的网站上,他声明允许静态成员的类内初始化会违反单一定义规则 (ODR)。
但是,这些答案似乎过于简单化。编译器完全能够在需要时解决 ODR 问题。例如,考虑 C++ header 中的以下内容:
struct SimpleExample
{
static const std::string str;
};
// This must appear in exactly one TU, not a header, or else violate the ODR
// const std::string SimpleExample::str = "String 1";
template <int I>
struct TemplateExample
{
static const std::string str;
};
// But this is fine in a header
template <int I>
const std::string TemplateExample<I>::str = "String 2";
如果我实例化 TemplateExample<0>
在多个翻译单元中,编译器/链接器魔法开始了,我得到了一份 TemplateExample<0>::str
在最终的可执行文件中。
所以我的问题是,鉴于编译器显然可以解决模板类的静态成员的 ODR 问题,为什么它不能对非模板类也这样做?
编辑:Stroustrup 常见问题解答可用here .相关句子是:
However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects
然而,那些“复杂的链接器规则”似乎确实存在并且在模板案例中使用,那么为什么不在简单案例中呢?
最佳答案
好的,下面的示例代码演示了强链接器引用和弱链接器引用之间的区别。之后我将尝试解释为什么在 2 之间进行更改会改变由链接器创建的生成的可执行文件。
原型(prototype).h
class CLASS
{
public:
static const int global;
};
template <class T>
class TEMPLATE
{
public:
static const int global;
};
void part1();
void part2();
file1.cpp
#include <iostream>
#include "template.h"
const int CLASS::global = 11;
template <class T>
const int TEMPLATE<T>::global = 21;
void part1()
{
std::cout << TEMPLATE<int>::global << std::endl;
std::cout << CLASS::global << std::endl;
}
file2.cpp
#include <iostream>
#include "template.h"
const int CLASS::global = 21;
template <class T>
const int TEMPLATE<T>::global = 22;
void part2()
{
std::cout << TEMPLATE<int>::global << std::endl;
std::cout << CLASS::global << std::endl;
}
main.cpp
#include <stdio.h>
#include "template.h"
void main()
{
part1();
part2();
}
我接受这个示例完全是人为的,但希望它能够说明为什么“将强链接器引用更改为弱链接器引用是一项重大更改”。
这会编译吗?不,因为它有 2 个对 CLASS::global 的强引用。
如果您删除对 CLASS::global 的强引用之一,它会编译吗?是的
TEMPLATE::global 的值是什么?
CLASS::global 的值是什么?
弱引用是undefined,因为它依赖于链接顺序,这使得它充其量是模糊的,并且依赖于链接器无法控制。这可能是可以接受的,因为不将所有模板保存在一个文件中是不常见的,因为编译工作需要原型(prototype)和实现。
但是,对于类静态数据成员,因为它们在历史上是强引用,并且不能在声明中定义,因此在实现文件中具有带有强引用的完整数据声明是规则,现在至少是常见的做法。
事实上,由于链接器会因违反强引用而产生 ODR 链接错误,因此通常的做法是拥有多个目标文件(要链接的编译单元),它们有条件地链接以改变不同硬件和软件组合的行为有时是为了优化好处。知道您是否在链接参数中犯了错误,您会收到一个错误,提示您忘记选择特化(无强引用),或选择了多个特化(多个强引用)
您需要记住,在引入 C++ 时,8 位、16 位和 32 位处理器仍然是有效的目标,AMD 和 Intel 有相似但不同的指令集,硬件供应商更喜欢封闭的私有(private)接口(interface)而不是开放标准.构建周期可能需要数小时、数天甚至一周。
关于c++ - 为什么静态成员的类内初始化会违反 ODR?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18909608/
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 5 年前。 Improve
在 C# 静态方法中是否有一种方法可以引用定义该方法的类型? 在实例方法中,您可以通过以下方式确定类型: public void Foo() { Type type = this.GetTyp
WPF:静态、动态资源以及资源词典 静态资源与动态资源 我们常常会使用样式或者控件模板放在Window.Resources中,比如这样: 静态资源与动态资源使用如下: <Window
任何人都知道如何在共享/静态函数中动态加载控件?该函数本身位于 mustinherit/abstract 类中。 (这是 VB 中的 ASP.NET 项目)我想做这样的事情: VB: Publ
在我看来,静态/强类型编程语言最宝贵的一点是它有助于重构:如果/当您更改任何 API,那么编译器会告诉您该更改破坏了什么。 我可以想象用运行时/弱类型语言编写代码......但我无法想象没有编译器的帮
正如我的名字所暗示的,我是一名 .NET 开发人员,但我对 Java 的兴趣越来越大,并且我有兴趣学习更多其他语言,因为这有助于我学习更多关于编程的知识。 无论如何,我的问题是:不带参数/不使用状态的
我在java中使用WireMock来 stub POST请求。该请求返回一个存储在我本地的 json 正文文件。 stub 看起来像这样: wireMockServer.stubFor(get(url
Python 是否有类构造函数的机制,即每当首次引用类时(而不是创建该对象的实例时)调用的函数?我知道其他一些语言中也存在这种情况,但我还没有在 Python 中遇到过。 基本上,我想初始化该函数中的
Python 是否有类构造函数的机制,即每当首次引用类时(而不是创建该对象的实例时)调用的函数?我知道其他一些语言中也存在这种情况,但我还没有在 Python 中遇到过。 基本上,我想初始化该函数中的
这个问题已经有答案了: What is the difference between dynamic and static polymorphism in Java? (14 个回答) 已关闭 4 年
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Static initializer in Java 我想知道这个静态的东西(抱歉,这是我第一次遇到这个)对一个类有
如果c++应用程序是按以下方式组织的 //file1.cpp static Y sgObj = X::getInitObject(0); //declared in file scope //fil
我有一个抽象类(AvergedDataRecord),我需要进一步抽象(DataRecord),这样我就可以将它扩展到原始类和一个新的具体类(SummedDataRecord),并且我在获取某些方法时
我正在尝试制作一个字符串枚举。这是我到目前为止所得到的, private class TypedEnum : IEnumerable { public IEnumerator GetEnume
我选修了一门名为“安全代码”的类(class),在下一个作业中,我们应该对一些 C 文件和 JavaEE Web 项目进行静态/动态分析。 我检查了“源监视器”并在 C 文件上运行它,但是(除非我不知
我有两个类,一个是登录类,一个是用户类。在 loggedIn 类中,我想显示我在用户登录时所做的共享首选项。 loginPrefs = getSharedPreferences("loginprefe
我在同一个 Activity 中有两个静态 fragment ,在“fragmentA”中我有一个自定义列表,当一个项目被点击时必须在“fragmentB”中出现一个细节,细节只在我改变屏幕方向时出现
在 Java 中是未修改方法变量,缺少final,每次都重新初始化限定符 静态方法 实例方法 如果 1. 或 2.(或两者)的答案是 final 限定符允许 Java 执行优化并存储方法变量只有一次?
我有两个类相互交互。第一个是中心的,如下: public class Datenbank { double winkelPanel = 0; double groessePanel = 0; doub
我有一个 mysql 数据库,它连接基于 Web 的 php 应用程序和 FoxPro 应用程序(是的,foxpro)。在之前的“开发人员”被解雇后开始处理这个问题。 无论如何,我熟悉 AES_Enc
我是一名优秀的程序员,十分优秀!