Приведение объекта к ссылке?

В последнее время я читал код OSS и наткнулся на этот своеобразный фрагмент:

class Foo { ..... };
void bar() {
    Foo x;
   Foo *y=new Foo();
   x=(const Foo &) *y;
}

На всю жизнь я не могу найти документацию о поведении приведения объекта к константной ссылке.


person Afiefh    schedule 07.05.2011    source источник
comment
Я пытаюсь понять фрагмент кода, который я нашел.   -  person Afiefh    schedule 08.05.2011
comment
Вы уверены, что не пропустили (пропустили) разыменование на y?   -  person Xeo    schedule 08.05.2011
comment
О, действительно я. но я до сих пор не знаю, что означает приведение объекта к константной ссылке...   -  person Afiefh    schedule 08.05.2011
comment
Каждый раз, когда вы видите приведение в стиле C в коде C++, это почти наверняка неправильно.   -  person    schedule 08.05.2011
comment
Есть ли у Foo operator= не по умолчанию?   -  person n0rd    schedule 08.05.2011
comment
@Afiefh: Итак, с вашим редактированием вам все еще нужно объяснение кода? В противном случае было бы неплохо полностью удалить вопрос, поскольку он не имеет никакой цели, когда вы спрашиваете о коде, который странен только потому, что вы неправильно его прочитали.   -  person jalf    schedule 08.05.2011
comment
Есть ли отдельная реализация operator= для аргументов типа Foo & и const Foo &?   -  person n0rd    schedule 08.05.2011
comment
@n0rd: проверьте его редактирование. Нет никакой тайны   -  person jalf    schedule 08.05.2011
comment
Джалф: Да, я до сих пор не знаю, что он делает. Я удалю вопрос через несколько минут, если никто не ответит.   -  person Afiefh    schedule 08.05.2011
comment
@Afiefh: если у вас есть настоящий вопрос, не удаляйте его (но вместо того, чтобы просто внести правку внизу, обновите весь вопрос, чтобы было ясно, о чем вы спрашиваете. Нам все равно, что вы неправильно прочитали code 20 минут назад, мы хотим знать, каков ваш вопрос сейчас.   -  person jalf    schedule 08.05.2011
comment
Я отредактировал ваш вопрос, чтобы первый фрагмент кода соответствовал фактическому коду, и удалил явное редактирование. Я не изменил текст вопроса, поэтому, пожалуйста, обновите его, если он не отражает то, что вы хотели спросить.   -  person jalf    schedule 08.05.2011
comment
@jalf: я откатился, так как это противоречит цели вопроса, и получил причину, по которой исходная (неверно прочитанная) версия вообще будет работать. :)   -  person Xeo    schedule 08.05.2011
comment
@Xeo: но сейчас вопрос не соответствует ответу. Вопрос касается приведения указателя к ссылке, а принятый ответ касается присваивания ссылки значению, при этом приведение застряло между ними без особой причины.   -  person jalf    schedule 08.05.2011
comment
@Afiefh: пожалуйста, решите, что вы хотите спросить, и удалите любую информацию, не относящуюся к этому. Если вы хотите узнать о приведении указателя к ссылке, то редактирование просто вводит в заблуждение и должно быть удалено. Если вы хотите понять фактический код, то редактирование имеет значение, и остальная часть вопроса должна быть обновлена, чтобы соответствовать этому. И, конечно же, принятым ответом должен быть тот, который отвечает на вопрос, который вы на самом деле задаете. Как сейчас, это просто сбивает с толку.   -  person jalf    schedule 08.05.2011
comment
@Afiefh: спасибо, теперь намного яснее, на что мы на самом деле должны ответить. (И с этим я превратил свой отрицательный голос в положительный) :)   -  person jalf    schedule 08.05.2011
comment
@jalf: Спасибо, обычно я не совершаю таких ошибок и не знал, что от меня требует приемлемый этикет переполнения стека. Я решил сохранить исходный текст и добавить новую информацию, чтобы любой, кто читает это впоследствии, не чувствовал, что некоторые вещи здесь не имеют отношения к сообщению.   -  person Afiefh    schedule 08.05.2011


Ответы (4)


x=(const Foo &) *y; – это назначение. Единственная причина, по которой я вижу явное приведение к константной ссылке, заключается в том, что Foo::operator=(const Foo &) вызывается для присваивания, если Foo::operator=(Foo &) также существует.

person n0rd    schedule 07.05.2011

Строка x=(const Foo &) y; вызывает неопределенное поведение.
Желательно избегать приведения типов в стиле C; их легко ошибиться. Вы заглушаете компилятор, так что они слишком опасны.

Изменить: этот ответ был актуален в то время, когда в вопросе y не было разыменовано до приведения к const Foo &. Ответ на вопрос после редактирования *y см. в ответе, данном n0rd.

person usta    schedule 07.05.2011
comment
@jalf: компилируется для меня с помощью g++ 4.4.5. Почему вы думаете, что не должно? - person usta; 08.05.2011
comment
Как вы думаете, почему так должно быть? Я согласен с тем, что он компилируется под тремя основными компиляторами (что меня удивило), но я все еще не понимаю, почему это должно быть так. Что в стандарте разрешает приведение от указателя к ссылочному типу? - person jalf; 08.05.2011
comment
Не понимаю, почему это поведение undefined. Это нехорошо из-за актерского состава в стиле C. Но переписать, чтобы использовать const_cast‹› (это все еще нехорошо), но все еще работает. - person Martin York; 08.05.2011
comment
Хорошо, после нескольких вопросов в чате SO C++ и 10 минут, потраченных на чтение стандарта, и еще 5 на работу с игрушечным примером вручную, я понял. Да, он компилируется, и да, это неопределенное поведение. Он превращается в reinterpret_cast, а reinterpret_cast в ссылочный тип эквивалентен приведению адреса аргумента к указателю на целевой тип с последующим разыменованием его. Таким образом, это эффективное приведение от Foo** к Foo*, которое правильно сформировано, потому что reinterpret_cast может свободно приводить типы указателей, а затем разыменовывать результат, получая UB - person jalf; 08.05.2011
comment
@jalf: Тогда вам придется объяснить это (поэтому нам не нужно также уступать стандарту). Мне кажется, что C-Cast следует преобразовать в простой const_cast‹› - person Martin York; 08.05.2011
comment
@Martin: Да, вы правы - он преобразуется в const_cast. *y дает lvalue типа Foo, а приведение просто добавляет const. - person Vitus; 08.05.2011
comment
@jalf, @Martin, @Vitus: Спасибо за отличную дискуссию, пока я не был в сети. Причина, по которой я был уверен, что он скомпилирован и является UB без поиска стандарта, заключалась в том, что я знал, как реализован boost::addressof. По сути, он приводит свой аргумент к char &, берет адрес результата и приводит его к указателю на тип аргумента. Теперь, проверяя это со стандартом, я вижу соответствующий раздел 5.2.10/10. - person usta; 08.05.2011
comment
@Vitus: сложная часть происходит потому, что он преобразуется в reinterpret_cast. В добавлении const мало волшебства - person jalf; 08.05.2011
comment
@Xeo, @jalf: указатель разыменовывается до приведения, поэтому он должен быть действительным const_cast. Разыменование, вероятно, было добавлено при редактировании вопроса. :) - person Vitus; 08.05.2011
comment
@Xeo: Очень хороший дополнительный вопрос с отличным ответом от @AndreyT! +1 - person usta; 08.05.2011

Интересно, что неправильное прочтение кода все еще возможно, если Foo имеет неявный конструктор, который принимает указатель Foo*.

#include <iostream>

class Foo{
public:
  Foo() {}
  Foo(Foo*) { std::cout << "Aha!\n"; }
};

int main(){
  Foo* pf = new Foo;
  Foo f = (const Foo&)pf;

  std::cin.get();
}

См. выходные данные в Ideone.
Интересно, что если вы сделаете конструктор явным, он покажет неопределенное поведение, объясняемое @уста.

person Xeo    schedule 07.05.2011

Вам нужно объявить x после y:

Foo* y = new Foo();
Foo& x = *y;

В качестве альтернативы:

Foo x;
Foo* y = new Foo();
x = (Foo&)*y;
person Seth Carnegie    schedule 07.05.2011
comment
Обратите внимание, что это не я писал, я пытаюсь понять это, и это работает так, как написано прямо сейчас. - person Afiefh; 08.05.2011
comment
Это не его код, он пытается найти объяснение тому, что он делает. - person Xeo; 08.05.2011