2017-01-26 20 views
-2

Итак, я писал код и хотел узнать прототип сложного оператора (например, operator*= или operator/=). Когда я посмотрел на него, я понял, что они должны возвращать ссылки. (Или, по крайней мере, мой источник указал, как, например: R& operator +=(K& a, S b);.) Ну .. Я тогда понял, что линия в моем коде может быть немного более опасным, чем он оказался:C++ - Что произойдет, если я верну a * = b; `?

// I have a really fancy Vector class I've been making. :P 
template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

Так .. Мне было интересно если это безвредно ... или вызовет ссылку на локальную переменную для утечки и вызовет все виды неопределенного поведения и общего хаоса. (Я склоняюсь к хаосу, и, как таковой, переписал его, как показано ниже.: P)

// I have a really fancy Vector class I've been making. :P 
template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    ret *= scale; 
    return ret; 
} 

Так .. да .. общий C++ "что если?" вопрос здесь. Было бы хорошо знать наверняка. (И я был слишком ленив, чтобы попробовать и сделать тест, чтобы увидеть, если моя программа остановилась и загорелась.: P)

EDIT: После закрепления выше код .. Я понял, что это может помочь поставить указанное соединение оператора здесь. : P

template<typename T, int N> 
inline Vector<T, N>& operator*=(Vector<T, N>& vec, T scale) { 
    for (int i = 0; i < N; i++) { 
     vec[i] *= scale; 
    } 
    return vec; 
} 

Так .. с кодом исправленного (и перепроверено) мне интересно, если с помощью этого первого варианта будет по-прежнему вызывает оборванную ссылку или нет (потому что тип возвращаемого operator*= это ссылка) ,

+2

Насколько я вижу, оба примера делают одно и то же: они возвращают ссылку на локальную переменную, которая сразу выходит из области видимости и больше не существует. –

+0

@JerryJeremiah Конечно, они не ... последнее, конечно, НЕ возвращает ссылку на локальную переменную. Первый ... ну это был мой вопрос! EDIT: Хорошо .. Я посмотрел на него снова, и я вижу это сейчас. Игнорируйте это. : P –

+0

@CorneliaXaos Возвращаемым типом обеих версий функции является вектор Vector & ', который является ссылкой, и вы возвращаете' ret', которая является локальной переменной. Поэтому вы возвращаете ссылку на локальную переменную. –

ответ

5

По соглашению, сложные операторы присваивания, такие как *=, должны возвращать ссылку на объект, который они изменяют, так как нет причин делать ненужную копию. Тем не менее, даже в вашем модифицированном примере вы получите ссылку «оборванную», поскольку вы все еще возвращаете ссылку на локальную переменную, которая будет уничтожена после возвращения функции. Вы должны возвращать значение вместо ссылки.

template <typename T, int N> 
Vector<T, N> operator*(Vector<T, N> const& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

Заметим также, что вы можете избавиться от ret если вы передаете vec по значению. Это может обеспечить более эффективный код клиента, если Vector<T, N> можно перемещать более эффективно, чем его можно скопировать.

template <typename T, int N> 
Vector<T, N> operator*(Vector<T, N> vec, T scale) { 
    return vec *= scale; 
} 
+0

Shoot .. Я набрал код неправильно .. XD –

+0

Да. Мне нужно сделать что-то похожее на последний пример, который вы предоставляете (но входной vec все равно должен быть const). –

+1

@CorneliaXaos: вход не должен быть 'const', это значение pass-by-value, которое либо копирует, либо перемещает операнд соответствующим образом. И тогда результат возвращает результат. –

0

У вас есть два варианта:

Если определить оператор в классе он принимает один параметр и изменение данных классов и возврат * это без возврата локальных переменного:

R& K::operator *=(S b); 

Если вы определяете оператор вне класса, он принимает два параметра, и вы изменяете этот параметр и возвращаете этот параметр, не возвращая локальную переменную:

R& operator *=(K& a, S b); 

От http://en.cppreference.com/w/cpp/language/operators под канонические Реализации они имеют следующий пример:

class X 
{ 
public: 
    X& operator+=(const X& rhs)  // compound assignment (does not need to be a member, 
    {        // but often is, to modify the private members) 
    /* addition of rhs to *this takes place here */ 
    return *this; // return the result by reference 
    } 

    // friends defined inside class body are inline and are hidden from non-ADL lookup 
    friend X operator+(X lhs,  // passing lhs by value helps optimize chained a+b+c 
        const X& rhs) // otherwise, both parameters may be const references 
    { 
    lhs += rhs; // reuse compound assignment 
    return lhs; // return the result by value (uses move constructor) 
    } 
}; 
1

(В то время как @ JosephThomson отвечают ниже «ответов» вопрос, это не прописано так просто, как я чувствую, что это должно быть так, что я ОКАЗЫВАЛОСЬ ответьте здесь.)

template<typename T, int N> 
inline Vector<T, N> operator*(const Vector<T, N>& vec, T scale) { 
    Vector<T, N> ret = vec; 
    return ret *= scale; 
} 

return ret *= scale; в приведенном выше не причина зависшей ссылки ошибка. Причина в том, что тип возврата - Vector<T, N> и составляет не ссылочный тип. Из-за этого, хотя operator*= определен для возврата ссылочного типа, копия создается, когда возвращается operator* (эффективно снимая ссылку).

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

  • Нет связанных вопросов^_^