内联静态常量与静态常量变量

10

我不清楚哪种解决方案更好,因为我不太明白它们之间的区别。我想要一个包含一些变量的文件,这些变量可以在整个程序中自由使用。我的第一次尝试如下:

头文件(Hosts.h)

#pragma once

#include <string>

namespace Some::Namespace {

using std::string;

class Hosts {
public:
    static const unsigned int SOME_DEVICE_PORT;
    static const string SOME_DEVICE_IP;
};
}

实现文件(Hosts.cpp)

#include <Network/Hosts.h>

namespace Some::Namespace {
    const unsigned int Hosts::SOME_DEVICE_PORT = 10100;
    const string Hosts::SOME_DEVICE_IP = "192.168.1.1";
}

后来我了解到inline关键字,它可以使实现文件不再需要,你可以仅在头文件中定义变量 - 就像这样:

带有inline的头文件(Hosts.h)

#pragma once

#include <string>

namespace Some::Namespace {

using std::string;

class Hosts {
public:
    static const unsigned int SOME_DEVICE_PORT = 10100;
    inline static const string SOME_DEVICE_IP = "192.168.1.1";
};
}

现在我的问题是:这些实现在变量实例数量方面有何不同?最好每个变量只有一个实例。但是,这两种解决方案是否会做到这一点,还有其他优化方面的陷阱吗?
谢谢。
2个回答

15

扩展Mayur的回答,这两种方法非常相似。

它们的主要区别在于在库(.dll等)中使用内联静态变量时。

对于带有inline变量,在编译阶段,每个使用它的翻译单元都会有一个实例,然后链接器将删除所有实例,只引用所有未被删除的翻译单元到唯一未被删除的实例。

对于非内联变量,将只有一个变量实例,然后所有翻译单元都将引用此变量。

在单个模块(.exe,.dll...)中,这两种用例的行为完全相同。

但是,在将多个.dll与.exe链接在一起时,使用inline变量时,每个模块都将具有一个实例,因此每个模块都将引用自己的实例。这可能(或可能不)是一个问题。由于您将它们声明为const,因此变量的值不会出现问题,但是如果您正在获取其地址进行某些比较或其他操作,则不同模块的地址将不同,这可能会导致问题。

这不会发生在非内联变量中,因为您应该从一个共享模块导出变量,并从所有其他模块引用它,这样整个程序就只有一个实例。


4

在C++中,内联声明的变量与内联函数声明具有相同的语义。它可以在多个编译单元中定义,必须在每个使用它的编译单元中定义,并且程序行为就像只有一个变量一样。

struct MyClass
{
    static const int sValue;
};
inline int const MyClass::sValue = 777;

甚至可以这样说:
struct MyClass
{
    inline static const int sValue = 777;
};

此外,需要注意的是constexpr变量隐式地是inline的,因此不需要使用constexpr inline myVar = 10;
(参考链接:ref

"...并且程序的行为就像确实只有一个变量一样" 但是,是否确实只有一个变量呢? - 7heViking
这取决于具体情况。每个目标文件都会有自己的变量,从某种意义上说。但在链接时,它们将合并为一个单一的文件。这就是为什么所有定义必须严格相同的重要性,也是“一次定义规则”的原因,否则你将会违反ODR(例如,当不同的翻译单元(TUs)使用不同的#define编译时,导致该变量的不同定义),这会导致“未定义行为”。 - ddevienne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接