Возвращение константной ссылки
От: wayfaring  
Дата: 30.12.11 05:55
Оценка:
Добрый день.

Легален ли следующий код:

const std::string & function( const std::string & str )
{
    return str;
}
Re: Возвращение константной ссылки
От: night beast СССР  
Дата: 30.12.11 05:57
Оценка:
Здравствуйте, wayfaring, Вы писали:

W>Добрый день.


W>Легален ли следующий код:


W>const std::string & function( const std::string & str )
W>{
W>    return str;
W>}


да
Re: Возвращение константной ссылки
От: SullenMan  
Дата: 30.12.11 06:07
Оценка:
Здравствуйте, wayfaring, Вы писали:

W>Добрый день.


W>Легален ли следующий код:


W>
W>const std::string & function( const std::string & str )
W>{
W>    return str;
W>}
W>


да, только зачем такое?
Re: Возвращение константной ссылки
От: ononim  
Дата: 30.12.11 06:52
Оценка: 1 (1) +3
W>Легален ли следующий код:
легален, но будет летален в таком случае:
const std::string &s = function( "foo" )
printf("s=%s\n",s.c_str());//kaboom
Как много веселых ребят, и все делают велосипед...
Re: Возвращение константной ссылки
От: rg45 СССР  
Дата: 30.12.11 08:04
Оценка:
Здравствуйте, wayfaring, Вы писали:

W>Легален ли следующий код:

W>...

Вот о чем подумалось. С появлением rvalue references появился способ обрабатывать временные объекты отдельно от остальных. И теперь можно защищать подобные функции от опасного использования, например так:

const std::string& function( const std::string& str)
{
    return str;
}
std::string function(std::string&& str) 
{
    return str;
}

Перегрузка, принимающая аргумент как rvalue reference, возвращает результат по значению. Благодаря этому использование function становится безопасным в любых вариантах:

std::string text = "Hello, World!";

const std::string& s1 = function(text);
const std::string& s2 = function("Happy New Year!"); //OK!

Хотя в некоторых случаях такой прием будет приводить к нежелательному копированию, например:

std::cout << function("bla-bla=bla") << std::endl;
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Возвращение константной ссылки
От: Masterkent  
Дата: 30.12.11 08:08
Оценка:
ononim:

W>>Легален ли следующий код:

O>легален, но будет летален в таком случае:
O>
O>const std::string &s = function( "foo" )
O>printf("s=%s\n",s.c_str());//kaboom
O>

Это проблемы вызывающего кода. Так же, как и в случае с

std::string s = function(0);

или

// если из function вернуть строку по значению, будет то же самое
char const *s = function("foo").c_str();
std::cout << s;
Re[3]: Возвращение константной ссылки
От: ononim  
Дата: 30.12.11 08:12
Оценка:
я же написал — что это легально, но к примеру у меня в привычках есть принимать возвращаемое значение-объект в конст-ссылку, и подозреваю не у меня одного, так что вышеописанный код — западло, но в определенных случаях (жесткая оптимизация) может быть оправдано
Как много веселых ребят, и все делают велосипед...
Re[4]: Возвращение константной ссылки
От: Кодт Россия  
Дата: 30.12.11 09:18
Оценка:
Здравствуйте, ononim, Вы писали:

O>я же написал — что это легально, но к примеру у меня в привычках есть принимать возвращаемое значение-объект в конст-ссылку, и подозреваю не у меня одного, так что вышеописанный код — западло, но в определенных случаях (жесткая оптимизация) может быть оправдано


Странная привычка. Экономия на cctor? Так ведь компилятор умеет экономить сам, выполняя RVO.

Код с протягиванием ссылки от параметра до возвращаемого значения может встречаться в разных expression template.
И задача его — не жёсткая оптимизация, а преобразование типов, либо просто терпимость к типам, которые noncopyable формально или по смыслу (тяжеловесные данные).
В отношении std::string это, конечно, выглядит пижонством и преждевременной оптимизацией.
Перекуём баги на фичи!
Re[4]: Возвращение константной ссылки
От: Masterkent  
Дата: 30.12.11 09:51
Оценка:
ononim:

O>я же написал — что это легально, но к примеру у меня в привычках есть принимать возвращаемое значение-объект в конст-ссылку, и подозреваю не у меня одного


Зачем так делать? Чем

Result f();
Result const &result = f();

лучше по сравнению с

Result f();
Result const result = f();

?
Правилами C++03 разрешалось создание любого конечного количества копий в обоих случаях. Правила C++11 требуют, чтобы ссылка result связывалась с исходным временным объектом непосредственно (без создания дополнительных копий), но очевидно, что для этого требуется тот же механизм, который можно использовать для RVO. Проверка доступности copy/move конструктора выполняется в контексте return statement вызываемой функции (инициализация ссылки снаружи функции эту проверку не устраняет). Любой вменяемый компилятор в обоих случаях поступит одинаково.

O>так что вышеописанный код — западло


Я так не считаю. Можно и при использовании возврата по значению накосячить:

#include <iostream>
#include <string>

std::string const &f1(std::string const &s)
{
    return s;
}

std::string f2(std::string const &s)
{
    return s;
}

std::string const &g1(std::string const &s)
{
    std::string const &result = f1(s);
    return result; // OK
}

std::string const &g2(std::string const &s)
{
    std::string const &result = f2(s);
    return result; // Ой!
}

int main()
{
    std::cout << g1("text") << std::endl; // OK
    std::cout << g2("text") << std::endl; // Ой!
}
Re[2]: Возвращение константной ссылки
От: Сыроежка  
Дата: 30.12.11 12:24
Оценка:
Здравствуйте, ononim, Вы писали:

W>>Легален ли следующий код:

O>легален, но будет летален в таком случае:
O>
O>const std::string &s = function( "foo" )
O>printf("s=%s\n",s.c_str());//kaboom
O>


Не могли бы вы объяснить, чем приведенный вами код будет "летален"?
Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

И чем ваш код отличается, например, от следующего кода

const int &r = 10;
Меня можно встретить на www.cpp.forum24.ru
Re[3]: Возвращение константной ссылки
От: rg45 СССР  
Дата: 30.12.11 12:50
Оценка: +1
Здравствуйте, Сыроежка, Вы писали:

С>Здравствуйте, ononim, Вы писали:


W>>>Легален ли следующий код:

O>>легален, но будет летален в таком случае:
O>>
O>>const std::string &s = function( "foo" )
O>>printf("s=%s\n",s.c_str());//kaboom
O>>


С>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: Возвращение константной ссылки
От: Сыроежка  
Дата: 30.12.11 13:07
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Сыроежка, Вы писали:


С>>Здравствуйте, ononim, Вы писали:


W>>>>Легален ли следующий код:

O>>>легален, но будет летален в таком случае:
O>>>
O>>>const std::string &s = function( "foo" )
O>>>printf("s=%s\n",s.c_str());//kaboom
O>>>


С>>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

R>Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.


Любопытно, почему у компилятора нет такой информации?! А на какой тогда по вашему объект возвращается ссылка?!
Меня можно встретить на www.cpp.forum24.ru
Re[5]: Возвращение константной ссылки
От: rg45 СССР  
Дата: 30.12.11 13:21
Оценка:
Здравствуйте, Сыроежка, Вы писали:

W>>>>>Легален ли следующий код:

O>>>>легален, но будет летален в таком случае:
O>>>>
O>>>>const std::string &s = function( "foo" )
O>>>>printf("s=%s\n",s.c_str());//kaboom
O>>>>


С>>>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>>>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

R>>Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.


С>Любопытно, почему у компилятора нет такой информации?! А на какой тогда по вашему объект возвращается ссылка?!


По принципу раздельной компиляции — эта функция может быть определена в другой единице трансляции. И внутреннее представление ссылок сравнить компилятор не может, потому, что во время компиляции их просто нет.
--
Справедливость выше закона. А человечность выше справедливости.
Re[6]: Возвращение константной ссылки
От: Сыроежка  
Дата: 30.12.11 13:52
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Сыроежка, Вы писали:


W>>>>>>Легален ли следующий код:

O>>>>>легален, но будет летален в таком случае:
O>>>>>
O>>>>>const std::string &s = function( "foo" )
O>>>>>printf("s=%s\n",s.c_str());//kaboom
O>>>>>


С>>>>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>>>>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

R>>>Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.


С>>Любопытно, почему у компилятора нет такой информации?! А на какой тогда по вашему объект возвращается ссылка?!


R>По принципу раздельной компиляции — эта функция может быть определена в другой единице трансляции. И внутреннее представление ссылок сравнить компилятор не может, потому, что во время компиляции их просто нет.


Честно признаюсь, не понял, какое значение имеет раздельная компиляция? При вызове этой функции (не важно, где она определена) создается неименованный объъект, и создается ссылка на этот объект. Далее определение функции знает, что она получила ссылку и эту ссылку возвращает. То есть внутри функции никакие новые ссылки не создаются. Поэтому не вижу причем, почему раздельная компиляции как-то должна повлиять. Если бы это было так, то можно было бы сказать, что половина кода на С++ некоректные. Ведь как происходит удаление временных объектов? Компилятор смотрит, есть ли на него ссылки (не важно, сколько этих ссылок), и если нет, то удаляет объект. То же самое происходит и в этом конкретном случае. После вызова функции компилятор смотрит, есть ли ссылки на объект (а они есть, причем, как вы считаете, их может быть даже две, так как по вашему из-за раздельной компиляции компилятор не знает, что эти две ссылки одни и те же), и если есть, то объяект не удаляетася. И этот механизм не влияет на наличие раздельной компиляции.
Меня можно встретить на www.cpp.forum24.ru
Re[7]: Возвращение константной ссылки
От: night beast СССР  
Дата: 30.12.11 14:04
Оценка: +2
Здравствуйте, Сыроежка, Вы писали:

W>>>>>>>Легален ли следующий код:

O>>>>>>легален, но будет летален в таком случае:
O>>>>>>
O>>>>>>const std::string &s = function( "foo" )
O>>>>>>printf("s=%s\n",s.c_str());//kaboom
O>>>>>>


С>>>>>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>>>>>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

R>>>>Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.


С>>>Любопытно, почему у компилятора нет такой информации?! А на какой тогда по вашему объект возвращается ссылка?!


R>>По принципу раздельной компиляции — эта функция может быть определена в другой единице трансляции. И внутреннее представление ссылок сравнить компилятор не может, потому, что во время компиляции их просто нет.


С>Честно признаюсь, не понял, какое значение имеет раздельная компиляция? При вызове этой функции (не важно, где она определена) создается неименованный объъект, и создается ссылка на этот объект. Далее определение функции знает, что она получила ссылку и эту ссылку возвращает. То есть внутри функции никакие новые ссылки не создаются. Поэтому не вижу причем, почему раздельная компиляции как-то должна повлиять. Если бы это было так, то можно было бы сказать, что половина кода на С++ некоректные. Ведь как происходит удаление временных объектов? Компилятор смотрит, есть ли на него ссылки (не важно, сколько этих ссылок), и если нет, то удаляет объект. То же самое происходит и в этом конкретном случае. После вызова функции компилятор смотрит, есть ли ссылки на объект (а они есть, причем, как вы считаете, их может быть даже две, так как по вашему из-за раздельной компиляции компилятор не знает, что эти две ссылки одни и те же), и если есть, то объяект не удаляетася. И этот механизм не влияет на наличие раздельной компиляции.


не знаю о каком С++ ты говоришь, но в том си, который я знаю, компилятор не считает никаких ссылок на временные объекты, а честно удаляет созданные объекты в конце выражения.

что нетрудно проверить:
struct test {
  test () { std::cout << __PRETTY_FUNCTION__ << std::endl; }
  test ( test const & ) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
  ~test () { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};

test const & foo ( test const & x ) { return x; }

int main () {
  test const & ref = foo( test() );
  std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Re[7]: Возвращение константной ссылки
От: rg45 СССР  
Дата: 30.12.11 14:09
Оценка: +1
Здравствуйте, Сыроежка, Вы писали:

С>Здравствуйте, rg45, Вы писали:


R>>Здравствуйте, Сыроежка, Вы писали:


W>>>>>>>Легален ли следующий код:

O>>>>>>легален, но будет летален в таком случае:
O>>>>>>
O>>>>>>const std::string &s = function( "foo" )
O>>>>>>printf("s=%s\n",s.c_str());//kaboom
O>>>>>>


С>>>>>Не могли бы вы объяснить, чем приведенный вами код будет "летален"?

С>>>>>Вы создаете временный неименованный объект, на который указывает константная ссылка. И пока ссулка будет жива, временный объект, на который сцществует константная сслыка, также будет жить, пока ссылка не выйдет за пределы области своей видимости.

R>>>>Тем, что, в общем случае, у компилятора нет информации о том, что функция возвращает ссылку именно на тот объект, который был передан функции в качестве аргумента. Следовательно, и оснований для продления времени жизни этого объекта у компилятора нет. Ну разжевывали же уже эту ситуацию, даже не один раз ЕМНИП.


С>>>Любопытно, почему у компилятора нет такой информации?! А на какой тогда по вашему объект возвращается ссылка?!


R>>По принципу раздельной компиляции — эта функция может быть определена в другой единице трансляции. И внутреннее представление ссылок сравнить компилятор не может, потому, что во время компиляции их просто нет.


С>Честно признаюсь, не понял, какое значение имеет раздельная компиляция? При вызове этой функции (не важно, где она определена) создается неименованный объъект, и создается ссылка на этот объект. Далее определение функции знает, что она получила ссылку и эту ссылку возвращает. То есть внутри функции никакие новые ссылки не создаются. Поэтому не вижу причем, почему раздельная компиляции как-то должна повлиять. Если бы это было так, то можно было бы сказать, что половина кода на С++ некоректные. Ведь как происходит удаление временных объектов? Компилятор смотрит, есть ли на него ссылки (не важно, сколько этих ссылок), и если нет, то удаляет объект. То же самое происходит и в этом конкретном случае. После вызова функции компилятор смотрит, есть ли ссылки на объект (а они есть, причем, как вы считаете, их может быть даже две, так как по вашему из-за раздельной компиляции компилятор не знает, что эти две ссылки одни и те же), и если есть, то объяект не удаляетася. И этот механизм не влияет на наличие раздельной компиляции.


Ну хорошо, давай рассмотрим пример:
#include <string>
#include <iostream>

const std::string& foo(const std::string&);

int main()
{
  const std::string& text = foo("bla-bla");
  std::cout << text << std::endl; 
}

Код вполне wel-formed и компилятор его успешно компилирует. Вопрос: по каким признакам компилятор должен понять, что временному объекту, созданному для передачи в функцию foo, нужно продлить время жизни?
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: Возвращение константной ссылки
От: hmich  
Дата: 30.12.11 16:18
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>Зачем так делать? Чем


M>
Result f();
M>Result const &result = f();

M>лучше по сравнению с

M>
Result f();
M>Result const result = f();

M>?

В случае если сигнатура f изменится на

Result const & f();


(что бывает, например, когда f() член класса и значение сохраняется для использования в других функциях), вызывающий код не придется модифицировать чтобы он принимал возвращаемое значение по ссылке а не по значению.
Re[6]: Возвращение константной ссылки
От: Masterkent  
Дата: 30.12.11 18:49
Оценка:
hmich:

M>>Зачем так делать? Чем


M>>
Result f();
M>>Result const &result = f();

M>>лучше по сравнению с

M>>
Result f();
M>>Result const result = f();

M>>?

H>В случае если сигнатура f изменится на


H>
Result const & f();


H>(что бывает, например, когда f() член класса и значение сохраняется для использования в других функциях), вызывающий код не придется модифицировать чтобы он принимал возвращаемое значение по ссылке а не по значению.


Сомнительный аргумент. Таким невинным с виду изменением интерфейса можно и чей-нибудь код сломать:

class X
{
public:
    Result f();
    ....
};

void foo(X &x)
{
    Result const &result = x.f();
    modify(x);   // после этой строчки x.f() вернуло бы другой результат
    use(result); // используем старое значение x.f()
}

class X
{
public:
    Result const &f();
    ....
};

void foo(X &x)
{
    Result const &result = x.f();
    modify(x);   // после этой строчки значение по ссылке result изменилось
    use(result); // хотели использовать старое значение x.f(), а получили использование модифицированного объекта
}
Re[2]: Возвращение константной ссылки
От: c-smile Канада http://terrainformatica.com
Дата: 30.12.11 20:17
Оценка:
Здравствуйте, rg45, Вы писали:

А можно узнать что именно OK в этом коде:

const std::string& s2 = function("Happy New Year!"); //OK!


?

Кроме как получение reference на временный объект ничего не вижу. В обоих случаях.
Re[7]: Возвращение константной ссылки
От: hmich  
Дата: 30.12.11 20:21
Оценка:
Здравствуйте, Masterkent, Вы писали:

M>hmich:


M>Сомнительный аргумент. Таким невинным с виду изменением интерфейса можно и чей-нибудь код сломать:


M>
class X
M>{
M>public:
M>    Result const &f();
M>    ....
M>};

M>void foo(X &x)
M>{
M>    Result const &result = x.f();
M>    modify(x);   // после этой строчки значение по ссылке result изменилось
M>    use(result); // хотели использовать старое значение x.f(), а получили использование модифицированного объекта
M>}


Не спорю, этот прием имеет смысл только при работе с константными объектами.

class X1
{
public:
    Result const &f() const;
    ....
};

class X2
{
public:
    Result f() const;
    ....
};

template < class X > void foo(X const &x)
{
    Result const &result = x.f();
    ....
}


В этом случае foo работает с одинаковой производительностью и с X1, и с X2. Если мы принимаем результат функции по значению, то в случае с X1 мы получаем лишнее копирование.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.