问题 在C ++中定义常量C字符串的正确方法?


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

static char const* MY_CONSTANT = "Hello World";

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

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

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

  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 或者我可以更改代码以使其产生这样的类型?

6787
2017-09-30 01:13


起源

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


答案:


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

constexpr char const* MY_CONSTANT = "Hello World";

第一个例子:

static char const* MY_CONSTANT = "Hello World";

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

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

哪里 静态的 例如,如果你想要一个 常量 成员是每个实例或每个类:

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

如果我们要求const是每个类,那么我们需要使用 静态的 否则没有。如果您不允许使用,示例会略有变化 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" ;

但实质是相同的只是语法不同。

对于你的第二个问题 得到#92 自动降低顶级const,给出的一个例子如下:

const int   ci  = val;  
auto        g   = ci;

它说:

g的类型是int。

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

正在提到的例子如下:

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

8
2017-09-30 01:26



可悲的是,msvc 12不支持constexpr :-( - void.pointer
@ void.pointer你不需要 constexpr 答案并没有改变语法。我更新了答案以包含一个没有的例子 constexpr 同样。 - Shafik Yaghmour


constexpr auto& MY_CONSTANT = "Hello World";
  • MY_CONSTANT有类型 const char (&)[12]
  • 没有衰减(数组绑定不会丢失)
  • 一切都是常数 - 数组本身和参考(根据定义)
  • 一切都是constexpr(可以在编译时使用) - 数组本身和引用
  • 由于MY_CONSTANT具有内部链接 constexpr 并且可以在标题中使用

2
2017-09-30 08:08



用VC ++ static auto& MY_CONSTANT = "Hello World"; 可以用来代替。 - user2665887
static 与恒常无关。这意味着该函数在其他编译单元中不可见。 - NO_NAME


这是一种罕见的情况,你碰巧覆盖指向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;
}

0
2017-09-30 07:21





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

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

标题:

extern const char *const mystring;

资源:

extern const char *const mystring = "hello";

另外

标题:

extern const std::string mystring;

资源:

extern std::string mystring = "hello";


0
2017-09-30 14:17