【问题标题】:Const correctness for extern const pointers外部 const 指针的 const 正确性
【发布时间】:2015-11-06 02:15:49
【问题描述】:

我正在尝试定义可以在 cpp 文件中使用的常量字符串,这样既不能修改数据,也不能修改指针。链接器抱怨以下内容:

main.obj:错误 LNK2001:未解析的外部符号“char const * const g_someString"

示例代码:

//constants.h
extern const char * const g_someString;

//constants.cpp
const char * const g_someString = "Hello";

// main.cpp
int main()
{
    strcmp(g_someString, "Hello");
}

当 const char * const 被 const char * 替换时,不会发生这种情况。编译器(MSVC 2015)是否优化了 constants.cpp 中的 g_someString 定义?

【问题讨论】:

  • 链接器错误随着 constants.cpp 中定义之前的 extern 声明而消失
  • 确保constants.cpp 包含constants.h(并且您没有循环依赖)
  • void main 在 C++ 中是非法的,即使您的编译器提供了不符合标准的扩展,编写依赖于此类扩展的代码也不好
  • @M.M:我认为也许我们应该修复所有那些void main除了评论,在问题不相关的情况下。

标签: c++ pointers


【解决方案1】:

之前

const char * const g_someString = "Hello";

您需要将其声明为extern(例如通过包含标头),因为const 命名空间级别变量默认具有内部链接。


也就是说,您可以只在标题中定义字符串。单独的编译使您能够修改字符串而无需重建大量文件,但除此之外,恕我直言,这是过早的优化。


要使标题中的字符串定义正式inline 函数安全,如果需要,您需要字符串(或至少是指针)具有extern 链接。一种方法是利用单一定义规则中对模板的特殊豁免。例如。像这样:

// Perhaps best generated by some code generation facility:
template< class Dummy >
struct Strings_
{
    static char const* const some_string;
    static char const* const some_other_string;
};

template< class Dummy >
char const* const Strings_<Dummy>::some_string = "Blah!";

template< class Dummy >
char const* const Strings_<Dummy>::some_string = "Oh, well.";

using Strings = Strings_<void>;

然后像这样使用

inline void foo() { cout << Strings::some_string << endl; }

这里的Strings::some_string 指针在所有翻译单元中都是相同的。

另一种方法是在inline 函数中定义字符串。然后你可以使用例如一个枚举来命名它们。

enum String_id { some_string, some_other_string };

inline
auto strings( String_id const id )
    -> char const*
{
    switch( id )
    {
    case some_string:          return "Blah!";
    case some_other_string:    return "Oh, well.";
    }
    assert( false );    // Should never get here.
}

类似的用法

inline void foo() { cout << strings( some_string ) << endl; }

inline 函数具有extern 链接,因此在所有翻译单元中都是相同的。

【讨论】:

  • 单独编译也可以帮助编译器进行字符串池化。
  • 在标题中定义字符串的一个缺陷是,如果inline 函数使用这样的字符串,它会导致未定义的行为。 (并不是说你不应该在标题中定义字符串,只是必须意识到这个陷阱)
  • @M.M:谢谢,我没有想到这一点(尽管我曾经意识到这一点)。我只考虑是否在标题中通过外部链接提及如何做到这一点,但决定这只会使答案复杂化。现在我不太确定,嗯。无论如何,要在标题中定义字符串并使用外部链接,只需使用旧的模板化常量技巧。
  • 您能否发布一个链接到“旧模板化常量技巧”的示例?
  • @Karthik:SO 显然不如谷歌所期望的那样,因为简单的谷歌搜索没有发现任何东西。我已经在这里回答了无数次。虽然它可能是谷歌本身,因为它也在 Usenet 组等中讨论过。哦,好吧,然后添加到这个答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多