2017-01-17 2 views
15

Пусть Point быть класс, экземпляры которого могут быть явно отлиты в wxPoint:Безопасно ли возвращать литую ссылку?

class Point{ 
private: 
    int x; 
    int y; 
public: 
    explicit operator wxPoint() const 
    { 
     return wxPoint(x, y); 
    } 

    // More stuff 
} 

У меня есть функция, которая возвращает ссылку на объект типа Point. Заголовок такой функции:

const Point& GetPoint(); 

Мой вопрос: безопасно определить следующую Foo функцию?

const wxPoint& Foo() const{ 
    return (wxPoint&) GetPoint(); 
} 

Сначала я реализовал Foo с return (wxPoint) GetPoint();, но создал новый (локальный) объекта и, следовательно, полезное предупреждение. Показанный здесь код компилируется без предупреждений.

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

Объяснение того, что именно происходит при выборе ссылки таким образом, было бы действительно оценено.

+0

Это совершенно «безопасно» для определения этой функции. Существуют способы использования этой функции, которые могут вызвать проблемы, и есть способы, которыми бы это не было. –

+0

В любом случае, если вы хотите написать недостижимый код ... (Вызов любой функции-члена на возвращаемом объекте будет вызывать UB). – rustyx

+2

@PeteBecker Почему вы сказали, что это совершенно «безопасно» ?. По моей идее это совершенно небезопасно. – MRB

ответ

16

Фактически ваш оператор преобразования никогда не вызывается. Вы возвращаете ссылку на экземпляр point от GetPoint. Позже вы использовали аккомпанемент стиля C, который в вашем случае будет эквивалентен reinterpret_cast<> (см. here). Вы ссылаетесь на Point в ссылку на wxPoint, и эти два являются полностью несвязанными типами. С другой стороны, любая операция с возвращенной ссылкой - это неопределенное поведение.

Мое предложение всегда использовать операторы слияния C++. У них есть преимущества:

  • Стили стиля C++ проверяются компилятором.
  • Вы можете легко найти стили в стиле C++.
  • Стили стиля C++ выражают намерение программиста.
+1

Я полагаю, что OP надеялся, что оператор преобразования будет вызван. Если бы эта строка была «return (wxPoint) GetPoint();», то есть мы бы применили правильный тип? Это вообще возможно со ссылкой? –

+7

@ PeterA.Schneider, который будет ссылаться на оператор преобразования для создания временного wxPoint'а, но затем попытается связать «wxPoint &» с тем временным, который плохо сформирован. Проблема заключается в возвращаемом типе функции: вы не можете вернуть ссылку, если нет привязки ссылки. –

+0

@StoryTeller Можете ли вы сказать, какой тип актеров это? – MRB

4

Включение ссылки в несвязанный ссылочный тип небезопасно. Хотя сам листинг не имеет побочных эффектов, доступ к исходному объекту посредством ссылки другого типа имеет неопределенное поведение (если правила псевдонимов типов не являются исключением, как в случае с char, но это не применяется здесь, поскольку стандарт не указывает такое исключение для wxPoint).

Оператор преобразования не участвует и не имеет значения.


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

«C стиль» cast делает один из const_cast, static_cast или reinterpret_cast или их комбинации, в том порядке предпочтения. Не существует static_cast, который применяется к несвязанным ссылкам.

Единственное, что относится к преобразованию const Point& в wxPoint&, - это reinterpret_cast, за которым следует const_cast. reinterpret_cast:

6) Выражение lvalue типа T1 может быть преобразовано в ссылку на другой тип T2. Результатом является значение lvalue или xvalue, относящееся к тому же объекту, что и исходное lvalue, но с другим типом. Временное создание не производится, копирование не производится, не создаются конструкторы или функции преобразования. В результате ссылка может быть доступна только безопасно, если это разрешено правилами наложения спектров типа (см ниже)


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

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

Так как приведение в стиле C может сделать неинтерактивно reinterpret_cast, к нему также необходимо будет проявлять большую осторожность.

13

Другие ответы уже объяснили, что кастинг Point& к wxPoint& просто лежит на компилятор, говоря это, что объект ссылка обязан это wxPoint объект, который не является правдой. Ваша программа будет иметь неопределенное поведение, если вы попытаетесь получить доступ к объекту wxPoint через эту ссылку, потому что он не связан с объектом wxPoint. Иногда, когда вы лжете компилятору, он не может дать вам предупреждения и просто должен верить, что вы не делаете что-то безумное.

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

wxPoint Foo() const { 
    return GetPoint(); 
} 

Это будет использовать оператор преобразования для построения wxPoint, и возвратить ее по значению, которое OK. Попытка вернуться по ссылке, когда нет привязки ссылки, не совсем нормально.

+0

К сожалению, у меня есть другое ограничение: заголовок 'Foo()' не может быть изменен :( – Alejandro

Смежные вопросы