Здравствуйте, valexey_, Вы писали:
_>Вопрос — отличается ли семантика ссылки на константу от самой константы в следующем случае:
_>
_>Foo foo();
_>...
_>const Foo& a = foo();
_>const Foo b = foo();
_>
_>Соответственно тип Foo — произвольный.
Foo foo();
...
const Foo& a = foo(); // здесь будет ссылка на временный объект, который будет разрушен и следовательно ссылка будет невалиднаconst Foo b = foo(); // здесь получите полноценную копию
Здравствуйте, saf_e, Вы писали:
_>const Foo& a = foo(); // здесь будет ссылка на временный объект, который будет разрушен и следовательно ссылка будет невалидна
Здравствуйте, saf_e, Вы писали:
_>Здравствуйте, valexey_, Вы писали:
_>>Вопрос — отличается ли семантика ссылки на константу от самой константы в следующем случае:
_>>
_>>Foo foo();
_>>...
_>>const Foo& a = foo();
_>>const Foo b = foo();
_>>
_>>Соответственно тип Foo — произвольный.
_>
_>Foo foo();
_>...
_>const Foo& a = foo(); // здесь будет ссылка на временный объект, который будет разрушен и следовательно ссылка будет невалидна
_>const Foo b = foo(); // здесь получите полноценную копию
_>
Здравствуйте, valexey_, Вы писали:
_>const Foo& a = foo(); _>const Foo b = foo();
лично я приучил себя использовать первый вариант в надежде, что компилятор соптимизирует что-то там и разместить объект где-нибудь в легко доступном месте (хотя куда уж шустрее стека?)
но на практике так и не ощутил выигрыша
видимо, не умею готовить
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, valexey_, Вы писали:
_>>const Foo& a = foo(); _>>const Foo b = foo();
U>лично я приучил себя использовать первый вариант в надежде, что компилятор соптимизирует что-то там и разместить объект где-нибудь в легко доступном месте (хотя куда уж шустрее стека?) U>но на практике так и не ощутил выигрыша U>видимо, не умею готовить
Ну, можно в регистр запихать Но штука в том, что в обоих случаях на современных компиляторах лишней копии объекта не наблюдается. Да и оптимизации применяются вроде бы одни и те же.
Быть может есть различие в последующей жизни a и b? Может есть что-то такое что можно с 'a' сделать но нельзя с 'b' и наоборот?
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, valexey_, Вы писали:
_>>const Foo& a = foo(); _>>const Foo b = foo();
U>лично я приучил себя использовать первый вариант в надежде, что компилятор соптимизирует что-то там и разместить объект где-нибудь в легко доступном месте (хотя куда уж шустрее стека?) U>но на практике так и не ощутил выигрыша U>видимо, не умею готовить
Как-то это прошло мимо меня Всю жизнь избегал такого, опасаясь что объект будет разрушен и надеялся на return-value optimization
Здравствуйте, valexey_, Вы писали:
_>Здравствуйте, uzhas, Вы писали:
U>>Здравствуйте, valexey_, Вы писали:
_>>>const Foo& a = foo(); _>>>const Foo b = foo();
U>>лично я приучил себя использовать первый вариант в надежде, что компилятор соптимизирует что-то там и разместить объект где-нибудь в легко доступном месте (хотя куда уж шустрее стека?) U>>но на практике так и не ощутил выигрыша U>>видимо, не умею готовить
_>Ну, можно в регистр запихать Но штука в том, что в обоих случаях на современных компиляторах лишней копии объекта не наблюдается. Да и оптимизации применяются вроде бы одни и те же.
_>Быть может есть различие в последующей жизни a и b? Может есть что-то такое что можно с 'a' сделать но нельзя с 'b' и наоборот?
Тогда получается, что если компилятор не умеет делать return-value optimization, то первый вариант эффективнее. Больше никакой разницы не наблюдаю...
Здравствуйте, saf_e, Вы писали:
_>Тогда получается, что если компилятор не умеет делать return-value optimization, то первый вариант эффективнее. Больше никакой разницы не наблюдаю...
Не думаю что все так просто. Быть может семантика const_cast'а над этими значениями будет отличаться например.
Здравствуйте, valexey_, Вы писали:
_>Здравствуйте, saf_e, Вы писали:
_>>Тогда получается, что если компилятор не умеет делать return-value optimization, то первый вариант эффективнее. Больше никакой разницы не наблюдаю...
_>Не думаю что все так просто. Быть может семантика const_cast'а над этими значениями будет отличаться например.
Не думаю что тут есть какие-то сложности. Семантически ссылка на объект и сам объект отличаются только временем жизни. А в данном примере не отличаются и этим
Здравствуйте, saf_e, Вы писали:
_>>Не думаю что все так просто. Быть может семантика const_cast'а над этими значениями будет отличаться например.
_>Не думаю что тут есть какие-то сложности. Семантически ссылка на объект и сам объект отличаются только временем жизни. А в данном примере не отличаются и этим
Ну вот чуть другой пример, где поведение отличается на некоторых компиляторах:
#include <iostream>
using namespace std;
void foo(int* p) {*p=12;}
int main() {
const int& a = 42;
const int b = 42;
foo(const_cast<int*>(&a));
foo(const_cast<int*>(&b));
cout << a << " " << b << endl;
return 0;
}
Здравствуйте, valexey_, Вы писали:
_>Здравствуйте, saf_e, Вы писали:
_>>>Не думаю что все так просто. Быть может семантика const_cast'а над этими значениями будет отличаться например.
_>>Не думаю что тут есть какие-то сложности. Семантически ссылка на объект и сам объект отличаются только временем жизни. А в данном примере не отличаются и этим
_>Ну вот чуть другой пример, где поведение отличается на некоторых компиляторах:
_>
_>#include <iostream>
_>using namespace std;
_>void foo(int* p) {*p=12;}
_>int main() {
_> const int& a = 42;
_> const int b = 42;
_> foo(const_cast<int*>(&a));
_> foo(const_cast<int*>(&b));
_> cout << a << " " << b << endl;
_> return 0;
_>}
_>
Выполнение этого кода undefined behaviuor в чистом виде.
Здравствуйте, valexey_, Вы писали:
_>Здравствуйте, saf_e, Вы писали:
_>>>Ну вот чуть другой пример, где поведение отличается на некоторых компиляторах:
_>>>
_>>>#include <iostream>
_>>>using namespace std;
_>>>void foo(int* p) {*p=12;}
_>>>int main() {
_>>> const int& a = 42;
_>>> const int b = 42;
_>>> foo(const_cast<int*>(&a));
_>>> foo(const_cast<int*>(&b));
_>>> cout << a << " " << b << endl;
_>>> return 0;
_>>>}
_>>>
_>>Выполнение этого кода undefined behaviuor в чистом виде.
_>Для обоих случаев? И если да, то согласно чему это будет UB?
У вас нет гарантии что память в которой размещены константы будет доступна на запись, это раз.
И второе, компилятор с чистой совестью может полагать что значение констант, в данном коде, не будет изменено.
_>>>>#include <iostream>
_>>>>using namespace std;
_>>>>void foo(int* p) {*p=12;}
_>>>>int main() {
_>>>> const int& a = 42;
_>>>> const int b = 42;
_>>>> foo(const_cast<int*>(&a));
_>>>> foo(const_cast<int*>(&b));
_>>>> cout << a << " " << b << endl;
_>>>> return 0;
_>>>>}
_>>>>
_>>>Выполнение этого кода undefined behaviuor в чистом виде.
_>>Для обоих случаев? И если да, то согласно чему это будет UB?
_>У вас нет гарантии что память в которой размещены константы будет доступна на запись, это раз. _>И второе, компилятор с чистой совестью может полагать что значение констант, в данном коде, не будет изменено.
В случае const int& -- IMHO, есть. По аналогии с тем же 14.1/6, будет гарантировано const reference bound to temporary. Что в общем то и наблюдаем в случае gcc: 'a' в результате манипуляций меняется на 12, а вот 'b' нет.
Для пущей ясности, уберем литерал и заменим его на "переменную":
#include <iostream>
using namespace std;
void foo(int* p) {*p=12;}
int main() {
const int z = 42;
const int& a = z;
const int b = z;
foo(const_cast<int*>(&a));
foo(const_cast<int*>(&b));
cout << a << " " << b << " " << z << endl;
return 0;
}
Результат:
12 42 42
Таким образом z и b не изменились, а вот содержимое 'a' изменилось.
Результат одинаков на clang и gcc. Пробовал и с -O0 и c -O3
_>Результат одинаков на clang и gcc. Пробовал и с -O0 и c -O3
Впрочем, я не утверждаю что тут нет UB. Просто хочется разобраться. И очевидно отличия в семантике какие-то все же есть, коль вылезает разное поведение (пусть даже из за UB) на некоторых компиляторах.
Здравствуйте, valexey_, Вы писали:
_>>Результат одинаков на clang и gcc. Пробовал и с -O0 и c -O3
_>Впрочем, я не утверждаю что тут нет UB. Просто хочется разобраться. И очевидно отличия в семантике какие-то все же есть, коль вылезает разное поведение (пусть даже из за UB) на некоторых компиляторах.
Тут скорее вопрос как конкретный компилятор трактует код.
Могу сказать одно, практического смысла тут 0, такого кода стоит избегать. ИМХО, в любых практических аспектах разницы быть не должно.
Здравствуйте, valexey_, Вы писали:
_>>>согласно чему это будет UB?
7.1.5.1 4
Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
Дальше в стандарте идёт пример, где показано когда запись по указателю, полученному через const_cast, делать можно, а когда нельзя. Похожий на твой код там есть, и отнюдь не в разделе «можно».
_>>У вас нет гарантии что память в которой размещены константы будет доступна на запись, это раз.
Это ещё не самое страшное. Ужасы начинаются когда когда значение константы таки удаётся изменить. И тогда где-то в другом месте программы вмести «42» будет подставляться «12».
_>В случае const int& -- IMHO, есть. По аналогии с тем же 14.1/6, будет гарантировано const reference bound to temporary. Что в общем то и наблюдаем в случае gcc: 'a' в результате манипуляций меняется на 12, а вот 'b' нет.
_>Для пущей ясности, уберем литерал и заменим его на "переменную": _>Результат одинаков на clang и gcc. Пробовал и с -O0 и c -O3
Здравствуйте, watch-maker, Вы писали:
WM>Здравствуйте, valexey_, Вы писали:
_>>>>согласно чему это будет UB? WM>
7.1.5.1 4
WM>Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.
WM>Дальше в стандарте идёт пример, где показано когда запись по указателю, полученному через const_cast, делать можно, а когда нельзя. Похожий на твой код там есть, и отнюдь не в разделе «можно».
_>>>У вас нет гарантии что память в которой размещены константы будет доступна на запись, это раз. WM>Это ещё не самое страшное. Ужасы начинаются когда когда значение константы таки удаётся изменить. И тогда где-то в другом месте программы вмести «42» будет подставляться «12».
_>>В случае const int& -- IMHO, есть. По аналогии с тем же 14.1/6, будет гарантировано const reference bound to temporary. Что в общем то и наблюдаем в случае gcc: 'a' в результате манипуляций меняется на 12, а вот 'b' нет.
_>>Для пущей ясности, уберем литерал и заменим его на "переменную": _>>Результат одинаков на clang и gcc. Пробовал и с -O0 и c -O3
WM>Это всё UB, причём довольно неинтересное.
Когда UB интересное его начинают активно использовать и это еще хуже