Правильный способ определения константы C-string в C++?
большую часть времени я вижу постоянные c-строки, определенные как:
static char const* MY_CONSTANT = "Hello World";
на указатель не const
. Не будет ли более уместным сделать это, как показано ниже?
static char const* const MY_CONSTANT = "Hello World";
есть 2 цели с постоянными глобалами, как это, я думаю:
- не допускайте изменения строки
- не позволяйте переменной указывать на что-либо еще
Я просто предположил эти 2 цели были необходимы при определении постоянных строк.
еще одна интересная вещь заключается в том, что я могу сделать это:
int main()
{
auto MY_CONSTANT = "";
MY_CONSTANT = "Another String";
}
это говорит мне, что auto
выводит строку char const*
, а не char const* const
.
Итак, у меня есть два основных вопроса:
- каков наиболее подходящий способ определения постоянных строк в стиле c (я полагаю, постоянные указатели на что-то, является более общим вопросом?). Почему вы выбираете одно или другие?
- относительно моего примера с
auto
, это имеет смысл, почему он выбираетchar const*
(потому что это массив данных, который является постоянным, а не сам указатель). Мог бы я сделатьauto
выводимchar const* const
или я могу изменить код, чтобы он привел к такому типу?
4 ответов
Ну если это действительно константа то constexpr будет на C++11 способ сделать это:
constexpr char const* MY_CONSTANT = "Hello World";
первый пример:
static char const* MY_CONSTANT = "Hello World";
просто говорит, что у меня есть указатель на char const, который имеет статическую длительность хранения, которая, если она находится вне функции, сделает ее глобальной.
если мы требовали, чтобы указатель также был const, нам нужна вторая форма, введенная вами. Все зависит от того, действительно ли указатель должен const или нет. В большинстве случаев причина, по которой ваш код see без 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 верхнего уровня 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;
constexpr auto& MY_CONSTANT = "Hello World";
- MY_CONSTANT имеет тип
const char (&)[12]
- нет распада (граница массива не теряется)
- все постоянно - сам массив и ссылка (по определению)
- все constexpr (может использоваться во время компиляции) - сам массив и ссылка
- MY_CONSTANT имеет внутреннюю связь из-за
constexpr
и может использоваться в заголовках
Это редкий случай, когда случается, что вы перезаписываете указатель, который указывает на значение 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;
}
хорошо сделано для замечать const на части указателя! Многие этого не понимают.
чтобы предотвратить дублирование строкового литерала на единицу перевода (или упростить его для Строковой части оптимизатора), я предлагаю поместить фактические данные в исходный файл где-нибудь. Это также сохранит некоторую перекомпиляцию, если вы измените текст.
:extern const char *const mystring;
источник:
extern const char *const mystring = "hello";
как вариант
:extern const std::string mystring;
источник:
extern std::string mystring = "hello";