Постоянные массивы
Это хороший старый массив C:
int a[10];
И это хороший старый массив C, который const
:
const int b[10];
В С++ существует два способа определить std::array
, которые const
:
std::array<const int, 10> c;
const std::array<int, 10> d;
Являются ли эти два определения эквивалентными? Если да, то что такое идиоматический? Если нет, каковы различия?
Ответы
Ответ 1
Ну, исходный const int b[10];
полезен только тогда, когда вы можете инициализировать массив, поэтому оба примера std::array
не работают на практике.
1
std::array<const int, 10> c;
Это самый близкий к const int c[10];
. Проблема в том, что для него не будет конструктора по умолчанию, и поскольку элементы не изменяемы, бесполезно использовать это. Вы должны предоставить некоторую инициализацию для этого в конструкторе. As-is, это даст ошибку компилятора, потому что конструктор по умолчанию не инициализировал элементы.
Этот код означает, что c
является изменяемым, но сами элементы не являются. На практике, однако, на c
нет мутаций, которые не влияют на элементы.
2
const std::array<int, 10> d;
Это означает, что d
не изменяет, но элементы имеют изменяемый тип int
. Поскольку const
будет распространяться среди членов, это означает, что элементы по-прежнему не изменяются вызывающим. Как и в предыдущем примере, вам нужно инициализировать d
, потому что он const
.
На практике они будут вести себя одинаково относительно изменчивости, поскольку изменяемые операции на array
всегда касаются элементов.
Ответ 2
В верхнем определении выделяется массив постоянных целых чисел в стеке, тогда как второй выделяет постоянный массив переменных целых чисел. В первом случае вы должны определить содержимое массива при его объявлении, поскольку его содержимое является постоянным, и его нельзя изменить позже. Я предполагаю, что первая вторая декларация будет генерировать нечто вроде
const std::array<const int,10> c;
поскольку статический массив всегда выделяется в стеке, а указатель на его первый элемент не может быть впоследствии изменен.
Ответ 3
Они не эквивалентны - c.reference
is int&
, тогда как d.reference
- const int&
(не для того, чтобы вы могли использовать этот синтаксис для доступа к typedefs, но вы могли бы захватить тип путем вычитания аргумента шаблона и сообщить разница).
Но я почти уверен, что у tenfour есть ключевое наблюдение: "на c
нет мутаций, которые не влияют на элементы". Так как все, что вы на самом деле делаете с массивами, это то же самое, у них просто разные метаданные из-за их разных типов.
В основном случае я могу думать о том, где это будет иметь значение, если вы используете сам тип в интерфейсе (в отличие от принятия итератора или параметра шаблона диапазона). Я бы сказал, что, беря его как указатель или ссылочный параметр, вы должны const-qualify самого типа array
, поскольку он ничего не стоит вам и позволяет вызывающему пользователю использовать вашу функцию независимо от того, какой выбор они сделали. Вы можете const-qualify тип элемента, но тот, который вы используете, несовместим с другим, так что в принципе каждый должен согласиться с тем, что использовать, или же потребуется некоторое копирование. Думаю, это требует активной координации по стилю, поскольку я сомневаюсь, что вы получите всех в мире, чтобы согласиться с тем, что лучше. const int
, вероятно, имеет лучший случай, по принципу, что вы должны const
все, что можете, но я ожидаю, что int
- это то, что люди будут использовать, кто вообще не думал об этом, поскольку они привыкли ко всем те контейнеры С++ 03, которые не могут иметь тип значения const
.