Согласно вашему коду:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
Если вы проверите System.out.print (name.length),
, вы получите 3;
, что означает, что длина вашего имени равна 3
, ваш цикл работает от 0 до 3, который должен работать либо от «0 до 2», либо от «1 до 3»
Ответ
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
System.out.print(name[i] +'\n');
}
По сути, причина, по которой optional
и variant
не допускают ссылочные типы, заключается в том, что существует разногласие относительно того, что присваивание (и, в меньшей степени, сравнение) должно делать для таких случаев. optional
проще, чем variant
показать в примерах, поэтому я буду придерживаться этого:
int i = 4, j = 5;
std::optional<int&> o = i;
o = j; // (*)
Отмеченную линию можно интерпретировать как:
o
, такой, что &*o == &j
. В результате этой линии сами значения i
и j
остаются неизменными. o
, такое &*o == &i
все еще верно, но теперь i == 5
. Assign-through - это поведение, которое вы получаете, просто нажимая =
до =
[1117], rebind - более надежная реализация и именно то, что вам действительно нужно (см. Также this вопрос , а также доклад Мэтта Калабрезе о ссылочных типах ).
Другой способ объяснить разницу между (1) и (2) заключается в том, как мы могли бы реализовать обе эти возможности извне:
// rebind
o.emplace(j);
// assign through
if (o) {
*o = j;
} else {
o.emplace(j);
}
Документация Boost.Optional предоставляет это обоснование:
Семантика перепривязки для назначения инициализированных необязательных ссылок была выбрана для обеспечения согласованности среди состояний инициализации даже за счет отсутствия согласованности с семантикой голых ссылок C ++. Это правда, что
optional<U>
стремится вести себя как можно лучше, чем U, когда он инициализируется; но в случае, когдаU
равноT&
, это приведет к несовместимому поведению по отношению к состоянию инициализации lvalue.Представьте
optional<T&>
переадресацию присваивания ссылочному объекту (таким образом, изменяя значение ссылочного объекта, но не привязывая), и рассмотрите следующий код:optional<int&> a = get(); int x = 1 ; int& rx = x ; optional<int&> b(rx); a = b ;
Что делает присваивание?
[ 1151] Еслиa
не неинициализирован , ответ ясен: он связывается сx
(теперь у нас есть еще одна ссылка наx
). Но что, если a уже инициализирован ? это изменило бы значение ссылочного объекта (что бы это ни было); что не согласуется с другим возможным случаем.
Если бы
optional<T&>
присваивал так же, какT&
, вы никогда бы не смогли использовать присваивание Optional без явной обработки предыдущего состояния инициализации, если ваш код не способен функционировать, будь то после присваивания,a
алиасирует то же самое объект какb
или нет.То есть вам нужно было бы различать, чтобы быть последовательным.
Если в вашем коде привязка к другому объекту невозможна, то весьма вероятно, что привязка в первый раз также не подходит. В таком случае присвоение неинициализированному
optional<T&>
должно быть запрещено. Вполне возможно, что в таком сценарии является предварительным условием, что значение lvalue должно быть уже инициализировано. Если это не так, тогда связывание в первый раз в порядке, а повторное связывание - нет, что очень маловероятно. В таком сценарии вы можете назначить само значение непосредственно, например:blockquote>assert(!!opt); *opt=value;
Отсутствие соглашения о том, что должна делать эта строка, означало, что было проще просто полностью запретить ссылки , так что большая часть значений
optional
иvariant
может, по крайней мере, сделать это для C ++ 17 и начать быть полезной. Ссылки всегда могут быть добавлены позже - или так аргумент пошел. [Тысяча сто пятьдесят-пять]