【问题标题】:Correct way to define a constant C-string in C++?在 C++ 中定义常量 C 字符串的正确方法?
【发布时间】:2014-09-30 01:13:56
【问题描述】:

大多数时候我看到常量 C 字符串定义为:

static char const* MY_CONSTANT = "Hello World";

但是,指针本身不是const。像下面这样做不是更合适吗?

static char const* const MY_CONSTANT = "Hello World";

我认为有 2 个具有像这样的常量全局变量的目标:

  1. 不允许修改字符串
  2. 不允许变量指向其他任何东西

我只是假设在定义常量字符串时需要这两个目标。

另一件有趣的事是我被允许这样做:

int main()
{
    auto MY_CONSTANT = "";
    MY_CONSTANT = "Another String";
}

这告诉我auto 将字符串推断为char const* 而不是char const* const

所以我有两个主要问题:

  1. 定义常量 c 样式字符串的最合适方法是什么(我想常量指针指向某物,是更普遍的问题吗?)。为什么选择其中之一?
  2. 关于我的auto 示例,它选择char const* 是有道理的(因为它是恒定的数据数组,而不是指针本身)。我可以将auto 推导出为char const* const 还是我可以更改代码以使其产生这种类型?

【问题讨论】:

  • 你不是说const char* const吗?
  • @Adam 这两种形式都是有效的 C++。你的和我的一样。
  • auto 检测到的默认值是最小限制,这意味着不能重新分配变量的事实只是您的选择。你可以做auto const我想,如果你愿意,但最好不要把它强加给每个人。
  • 字符串文字可以绑定到const char *;您是否希望字符串变量保持不变取决于您。您问的问题与should I use const int i=0 or int i=0 相同
  • 你没有提到的另一个品种是char const s[] = "Hello, World!";。 (在 C++ 中,关键字 static 是多余的,因为命名空间范围 consts 默认为静态,但无论如何使用它是很实用的,以防有人将您的标头移植到 C 并且没有意识到这一点)。

标签: c++ c++11 constants auto cstring


【解决方案1】:

如果它真的是一个常量,那么 constexpr 将是 C++11 的方法:

constexpr char const* MY_CONSTANT = "Hello World";

第一个例子:

static char const* MY_CONSTANT = "Hello World";

只是说我有一个指向具有静态存储持续时间的 char const 的指针,如果它在函数之外,它将使其成为全局变量。

如果我们要求指针也是 const,那么我们需要您介绍的第二种形式。这完全取决于指针是否确实应该为 const 。在大多数情况下,您看到没有顶级 const 的代码的原因是因为他们只是忘记将其放入,而不是因为他们并不意味着指针也是 const。

static 会有所不同,例如,如果您希望 const 成员是每个实例还是每个类:

class A
{
        char const* const const_per_instance = "Other Const String";
    public:
        constexpr static char const* const const_per_class = "Hello World" ;
};

如果我们要求 const 是每个类的,那么我们需要使用 static 否则不需要。如果您不允许使用 constexpr,示例会略有变化:

class A
{
        char const* const const_per_instance = "Other Const String";
    public:
        static char const* const const_per_class  ;
};

char const* const A::const_per_class = "Hello World" ;

但本质是一样的只是语法不同。

对于您的第二个问题,Gotw #92 说 auto drops top level const,一个例子如下:

const int   ci  = val;  
auto        g   = ci;

它说:

g的类型是int。

记住,仅仅因为 ci 是 const (只读)没有任何 关系到我们是否希望 g 成为 const。这是一个单独的变量。如果 我们希望 g 是 const,我们会说 const auto,就像我们在上面的情况 c 中所做的那样

引用的例子如下:

int         val = 0;  
//..
const auto  c   = val;

【讨论】:

  • 遗憾的是 msvc 12 不支持 constexpr :-(
  • @void.pointer 你不需要 constexpr 答案不仅仅改变了语法。我更新了答案以包含一个没有 constexpr 的示例。
【解决方案2】:
constexpr auto& MY_CONSTANT = "Hello World";
  • MY_CONSTANT 的类型为 const char (&)[12]
  • 没有衰减(数组绑定没有丢失)
  • 一切都是不变的——数组本身和引用(根据定义)
  • 一切都是 constexpr(可在编译时使用)- 数组本身和引用
  • 由于constexpr,MY_CONSTANT 具有内部链接,可用于标头中

【讨论】:

  • 可以用VC++static auto& MY_CONSTANT = "Hello World";代替。
  • static 与恒常无关。这意味着该函数在其他编译单元中不可见。
  • 据我所知,constexpr 不会改变链接,所以你仍然需要static 吗?
【解决方案3】:

在极少数情况下,您确实会覆盖指向 const 值的指针,因此大多数开发人员会省略第二个 const,但语义这样确实是正确的:

static char const* const MY_CONSTANT = "Hello World";

或以这种形式:

static const char* const MY_CONSTANT = "Hello World";

如果声明是另一个 constexpr 函数的一部分,则只需要声明的 constexpr,如下所示:

static constexpr const char* const MY_CONSTANT = "Hello World";
static constexpr const char* Foo()
{
    // ...
    return MY_CONSTANT;
}

【讨论】:

    【解决方案4】:

    注意到指针部分的 const 做得很好!很多人都没有意识到这一点。

    为了防止每个翻译单元重复字符串文字(或使优化器的字符串池部分更容易),我建议将实际数据放在源文件的某个位置。如果您更改文本,这也将节省一些重新编译。

    标题:

    extern const char *const mystring;

    来源:

    extern const char *const mystring = "hello";

    或者

    标题:

    extern const std::string mystring;

    来源:

    extern std::string mystring = "hello";

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-12-12
      • 1970-01-01
      • 2011-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多