Здравствуйте, tdiff, Вы писали:
T>Другими словами, я хочу, чтобы стек выглядел вот так: T>[ссылка на объект ниже] T>[d1 или d2] T>и время жизни d1 или d2 совпадало с текущим скоупом. T>... T>а создавать без повода объекты на хипе тоже как-то не круто.
Здравствуйте, antropolog, Вы писали:
A>да, спасибо, разобрался, проблема в самом касте, и ссылка инициализируется не rvalue а ссылкой
Дело не в rvalue. Время жизни результата d1() — выражение, грубо говоря до точки с запятой ;. И только в исключительных случаях (специально оговоренных в стандарте) может быть продлено до конца блока, например const base &x = d1();
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>const base &x = d1();
ну собственно меня и заинтересовало чем принципиально тернарный оператор здесь отличается, потому как например в случае с const base& x = true ? d1() : d1(); провисшей ссылки не будет.
и не поверил своим глазам: MSVC++ рвёт сразу G++ и Clang++ по части соответствия стандарту: первый компилирует пример корректно, другие два — нет. Кто б мог подумать, а?
Здравствуйте, N. I., Вы писали:
NI>Разница в том, что во втором случае к моменту вызова f ссылка x указывает на мёртвый объект.
NI>Я вот тут решил другой трюк провернуть
NI>
NI>и не поверил своим глазам: MSVC++ рвёт сразу G++ и Clang++ по части соответствия стандарту: первый компилирует пример корректно, другие два — нет. Кто б мог подумать, а?
м... я так понимаю, очевидное предположение что bref_1.ref.f() -- это вызов функции удаленного объекта не соответствует действительности?
night beast:
NB>м... я так понимаю, очевидное предположение что bref_1.ref.f() -- это вызов функции удаленного объекта не соответствует действительности?
Я там несколько слукавил насчёт "стандарта" — C++17 всё-таки ещё не вышел По C++14 тернарный оператор может создать копию выбранного результата, и тогда да, bref_1.ref.f() может быть вызовом функции для удалённого объекта.
Здравствуйте, N. I., Вы писали:
NB>>м... я так понимаю, очевидное предположение что bref_1.ref.f() -- это вызов функции удаленного объекта не соответствует действительности?
NI>Я там несколько слукавил насчёт "стандарта" — C++17 всё-таки ещё не вышел По C++14 тернарный оператор может создать копию выбранного результата, и тогда да, bref_1.ref.f() может быть вызовом функции для удалённого объекта.
блин. как-так.
как D1Wrapper() может пережить конец выражения если напрямую нигде не используется?
Здравствуйте, antropolog, Вы писали:
EP>>const base &x = d1(); A>ну собственно меня и заинтересовало чем принципиально тернарный оператор здесь отличается, потому как например в случае с const base& x = true ? d1() : d1(); провисшей ссылки не будет.
Здесь будет следующее:
— тип обеих веток одинаков, вопросов о приведении не будет
— тернарный оператор возвращает значение
— это значение попадает в скрытый объект типа d1
— ссылка продлевает время его жизни
А тебе нужна логика вот примерно такая
// продлеватели жизни на все случаи
std::optional<d1> tmp1;
std::optional<d2> tmp2;
// для любых выражений, возвращающих объекты по значениюconst base& x = condition ? (const base&)(tmp1 = return_d1_byval()).value()
: (const base&)(tmp2 = return_d2_byval()).value() ;
// для конструкторовconst base& x = condition ? (tmp1.emplace(12,34), (const base&)tmp1.value())
: (tmp2.emplace("abc"), (const base&)tmp2.value()) ;
std::optional есть в C++17, а до того — есть boost::optional
Ну и на самом деле, два optional — это один variant.
Здравствуйте, Кодт, Вы писали:
К>std::optional есть в C++17, а до того — есть boost::optional
раз пошла такая пьянка, то и по optional спрошу.
какие-нибудь ограничения на размер или хранимые значения в нем есть?
а то не очень бы хотелось чтобы он для int занимал в два раза больше памяти чем нужно...
night beast:
NB>блин. как-так. NB>как D1Wrapper() может пережить конец выражения если напрямую нигде не используется?
Раньше было так: когда инициализируешь такую ссылку частью объекта (представленного prvalue выражением), то время жизни всего объекта целиком подлежит продлению:
The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except: [...]
В новой редакции это правило оставили, но, перечитав 5.2.5, я-таки осознал, что не понимаю, как данное правило можно применять теперь, если prvalue.x — это xvalue, а не prvalue, как было раньше (как компилятор узнает, что некое xvalue — это чей-то subobject?). Как минимум понятно, что guaranteed copy elision при получении результата тернарного оператора в том примере всё же быть не может, т.е. насчёт корректности примера я был не прав (похоже, без перечитывания всего стандарта выпендриваться с новыми фичами особо нельзя, стандартизаторы усё попоменяли, так не и знаешь, откуда ждать подвоха ).
Здравствуйте, night beast, Вы писали:
NB>раз пошла такая пьянка, то и по optional спрошу. NB>какие-нибудь ограничения на размер или хранимые значения в нем есть? NB>а то не очень бы хотелось чтобы он для int занимал в два раза больше памяти чем нужно...
Ну а куда ты вынесешь один бит признака "есть данные — нет данных"?
Экономить можно только в том случае, когда объект optional не независимый, а в составе, ну хотя бы, вектора.
template<class T, size_t N>
class optional_array {
bitset<N> present;
using memory = aligned_storage<sizeof(T), alignof(T)>::type;
array<memory, N> data;
const T& peek(size_t i) const {
return reinterpret_cast<const T&>(data[i]);
}
T& peek(size_t i) {
return reinterpret_cast<const T&>(data[i]);
}
public:
T* get(size_t i) {
assert(i < N);
return present[i] ? &peek(i) : nullptr;
}
void set(size_t i, const T& v) { // и то же самое для T&& и для emplace.if (present[i])
peek(i) = v;
else {
new(&peek(i)) T(v);
present[i] = true;
}
}
void reset(size_t i) {
if (present[i]) {
peek(i).~T();
present[i] = false;
}
}
~optional_array() {
for(size_t i = 0; i < N; ++i) reset(i);
}
optional_array(const optional_array& arr) { // и то же самое для &&for(size_t i = 0; i < N; ++i) if(arr.get(i)) set(arr.get(i));
}
};
Здравствуйте, N. I., Вы писали:
NB>>блин. как-так. NB>>как D1Wrapper() может пережить конец выражения если напрямую нигде не используется?
NI>Раньше было так: когда инициализируешь такую ссылку частью объекта (представленного prvalue выражением), то время жизни всего объекта целиком подлежит продлению: NI>
The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except: [...]
спасиб. наверно, пока такие трюки опасно применять...
Здравствуйте, Кодт, Вы писали:
NB>>раз пошла такая пьянка, то и по optional спрошу. NB>>какие-нибудь ограничения на размер или хранимые значения в нем есть? NB>>а то не очень бы хотелось чтобы он для int занимал в два раза больше памяти чем нужно...
К>Ну а куда ты вынесешь один бит признака "есть данные — нет данных"?
у себя в велосипеде я использую особые значения вроде INT_MIN (конкретная стратегия применят флаг или некоторое значение задается в треитсах)
NI>Разница в том, что во втором случае к моменту вызова f ссылка x указывает на мёртвый объект.
Почему, если base&& должна продлевать время жизни temporary?
У меня есть догадка, что происходит что-то вроде:
1. создаётся temporary d1() с типом d1&&
2. тип этого объекта конвертируется в base&&
3. результатом ternary является base&&, которая продлевает время жизни d1
3. этой ссылкой инициализируется ссылка base&& x, которая почему-то уже не продлевает жизни d1
In general, the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.