LINUX.ORG.RU

[C++] передача анонимного объекта по ссылке


0

1

Попались мне win32-исходники, надо портировать под линукс. Кроме прочего попалось мне сообщение об ошибке такого вида:

test_conv.cpp: In function ‘int main(int, char**)’:
test_conv.cpp:52:25: error: no matching function for call to ‘B::setData1(A)’
test_conv.cpp:52:25: note: candidate is:
test_conv.cpp:28:14: note: void B::setData1(A&)
test_conv.cpp:28:14: note:   no known conversion for argument 1 from ‘A’ to ‘A&’

В инете не нашёл ответа. Ну, обход был очевиден: избавиться от ссылки. Тогда анонимный объект копироваться не будет (как проверить наверняка?), а вот неанонимный объект будет.

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

Универсальным способом могла бы быть перегрузка: объект объявлен - автоматом выбирай по ссылке, объект анонимный - тогда без ссылки, он всё равно в месте вызова не может быть больше использован... или хм, может?.. Полюбому, перегрузка не работает. Как же тогда?

Вот мой минимальный пример:

class A {
        int data_;
public:
        A() {};
        ~A() {};
        int data() {return data_;};
};

class B {
        int data_;
public:
        B() {};
        ~B() {};

        void setData1(A& a) {
                data_ = a.data();
        };
        // error: no known conversion for argument 1 from ‘A’ to ‘A&’

        //void setData1(A a) {
        //        data_ = a.data();
        //};
        // error: call of overloaded ‘setData1(A&)’ is ambiguous

        //void setData1(const A& a) {
        //        data_ = a.data();
        //}
        // error: passing ‘const A’ as ‘this’ argument of ‘int A::data()’ discards qualifiers

        // ???
};

int main(int argc, char *argv[])
{
        A a;
        B b;

        b.setData1( a ); // OK
        b.setData1( A() ); // error

        return 0;
}
★★★★★

Ответ на: комментарий от gag

я не о том. Может быть можно объявить ее как

int data() const {return data;};
           ^^^^^

тогда передача по константной ссылке может получиться

phoenix ★★★★ ()
void setData1(A& a) {
                data_ = a.data();
        };

кури термины rvalue и lvalue, нельзя в функцию передать объект созданный во время вызова функции, потому как он временный и константный

setData1(A()) - нельзя так

s0L ()

Терли уже... это «защита от дурака», типа в такой ситуации или забыто const A& или нефига анонимные объекты передавать (его там поменяют а потом все изменения пропадут).

Тем не менее есть ситуации когда такое запрещенное поведение необходимо (удобно) - например создали анонимно поток, передали его ф-ии, та в него отписалась, поток закрылся - все нормально. В 0x расширили синтаксис что бы такие вещи реализовывать, а я делаю напр так:

class A{
...
   A& self(){ return *this; }
};
...

void f(A&);
...

f( A().self() );

AIv ★★★★★ ()
Ответ на: комментарий от s0L

> нельзя в функцию передать объект созданный во время вызова функции, потому как он временный и константный

во первых НЕ константный, во вторых почему нельзя? Даже временный объект живет до ; после вызова ф-ии. Это запрещено стандартом де-юре, но де-факто ничему не противоречит.

AIv ★★★★★ ()
Ответ на: комментарий от AIv

>во первых НЕ константный..Это запрещено стандартом де-юре, но де-факто ничему не противоречит.

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

s0L ()
Ответ на: комментарий от s0L

Укажите мне пожалуйста хотя бы на одно нарушение логики и здравого смысла в приведенном примере, почему оно НЕ ДОЛЖНО РАБОТАТЬ? Только пожалуйста аргументированно.

AIv ★★★★★ ()
Ответ на: комментарий от AIv

>в приведенном примере...почему оно НЕ ДОЛЖНО РАБОТАТЬ?

о каком примере идет речь? если о том что ты написал, то читай внимательней, я не говорил что это не будет работать.

s0L ()
Ответ на: комментарий от AIv

>ТОгда если оно работает, почему не надо так делать?

да делай на здоровье, это уже твои проблемы. чем больше быдлокодеров, тем больше ценятся профессионалы

s0L ()
Ответ на: комментарий от s0L

То есть аргументов кроме как ярлычОк «быдлокодера» повесить у Вас нету? А Вы дражайший «Профессионал» мой код вообще видели? Какими задачами я занимаюсь знаете?

AIv ★★★★★ ()
Ответ на: комментарий от AIv

>То есть аргументов кроме как ярлычОк «быдлокодера» повесить у Вас нету? А Вы дражайший «Профессионал» мой код вообще видели? Какими задачами я занимаюсь знаете?

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

s0L ()
Ответ на: комментарий от s0L

То есть на основе куска кода в 5 строк Вы способны составить мнение о моей квалификации как программиста и повесить ярлык быдлокодера? У Вас либастрал какой версии?

Не знаю насколько Вы там профессиональны, но Вы либо просто дурак, либо крайне несимпатичный человек с зашкаливающем ЧСВ. В любом случае, мне искренне жаль Вас, Ваших близких, и тех коллег на работе, которые вынуждены терпеть Ваш «высокий профессионализЪм».

AIv ★★★★★ ()
Ответ на: комментарий от s0L

Так Вы ж со мной дела не имеете, откуда же Вы знаете какой я?;-)

Сходите к психотерапевту, он поможет;-)

AIv ★★★★★ ()
Ответ на: комментарий от AIv

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

s0L ()
Ответ на: комментарий от s0L

> но это не значит, что надо так делать.

Бред. Можно и допустимо. Кто-то кажется мало production кода писал. Либо аргументируйте (да, мне тоже интересно!), либо удержитесь, пожалуйста, от таких вбросов.

anonymous ()
Ответ на: комментарий от s0L

Вы меня позабавили. Очень по ЛОРовски - сказать что так делать нельзя, на вопрос «почему»? сказать «потому что нельзя», и еще окрестить себя профессионалом. Если щас такие профессионалы пошли, я пожалуй побуду быдлокодером...

AIv ★★★★★ ()
Ответ на: комментарий от namezys

>можно. если функа хочет ссылку на константный объект

еп, тут ваще кто нить читает посты прежде чем отвечать?

s0L ()
Ответ на: комментарий от anonymous

когда кажется, креститься надо. удержаться или нет я сам решу, не спрашивая анонимусов.

s0L ()
Ответ на: комментарий от s0L

> правильно оставить только такой метод:

void setData1(const A& a)

плюсую

aho ()
Ответ на: комментарий от phoenix

О чём я в С++ чаще всего забываю, так это о константных методах! А как раз все get-методы должны быть так помечены. Вот когда qt используешь, то там всё пестрит ими - не забудешь.

gag ★★★★★ ()
Ответ на: комментарий от Miguel

Да, это один из тривиальных обходов.

gag ★★★★★ ()
Ответ на: комментарий от s0L

Оно-то да, но только с напоминанием от phoenix.

gag ★★★★★ ()
Ответ на: комментарий от AIv

В приведённом мною примере действительно временный объект не изменяется. Надо сейчас подумать применение, чтобы было видно, что его можно поменять и это будет нужно снаружи. Скажем, для дургого временного объекта?.. Типа, setData(C(A()))?..

gag ★★★★★ ()
Ответ на: комментарий от s0L

Кстати, в самом начале своего вопроса я указал, что портирую с win32 (visual studio). Т.е. оно там компилируется и работает - так можно. Ну, если функция поменяет объект - не страшно, изменения пропадут, никого не тронув.

gag ★★★★★ ()
Ответ на: комментарий от gag

Ё-моё, тебе же всё объяснили: [C++] передача анонимного объекта по ссылке (комментарий)

Ту часть стандарта писали гномеры и они решили что никому не нужно передавать свежесозданный объект в функцию, которая его изменяет. Они ошиблись, теперь програмёрам приходится писать костыли типа того, что показал AIv или так:

#include<fstream>
template<class T>
T & ref(T & newlycreatedobj)
{
        return const_cast<T&>(newlycreatedobj);
}

void savetofile(std::ofstream & stream)
{
        stream << "saved\n";
}
int main(int argc, char *argv[])
{
        //savetofile(std::ofstream("/tmp/HAHAHA"));//ошибка: invalid initialization of non-const reference of type ‘std::basic_ofstream<char>&’ from an rvalue of type ‘std::ofstream’
        savetofile(ref(std::ofstream("/tmp/HAHAHA")));//ok
        return 0;
}


legolegs ★★★★★ ()
Ответ на: комментарий от legolegs

> Ту часть стандарта писали гномеры

Так заядлые Сшники работают над стандартом С++? Чтобы его более Сшным сделать что-ли?

Спс за пример.

gag ★★★★★ ()
Ответ на: комментарий от legolegs
g++ -Wall -g const_cast.cpp -o const_cast
const_cast.cpp: In function ‘int main(int, char**)’:
const_cast.cpp:15:52: error: invalid initialization of non-const reference of type ‘std::basic_ofstream<char>&’ from an rvalue of type ‘std::ofstream {aka std::basic_ofstream<char>}’
const_cast.cpp:3:5: error: in passing argument 1 of ‘T& ref(T&) [with T = std::basic_ofstream<char>]’
gag ★★★★★ ()
Ответ на: комментарий от gag

>> Ту часть стандарта писали гномеры

Так заядлые Сшники работают над стандартом С++?

Нет, это была метафора. «гномеры» - люди с мышлением «это мало кому надо, так что мы это вырежем/запретим».

error:

Да, я забыл, что сделал пример ошибочным и скопипастил неглядя.

Конечно-же

T & ref(const T & newlycreatedobj)

legolegs ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.