2015-06-23 3 views
2

В дополнение к ответам 1, 2, 3 и , предположим следующие методыВозвращение константную ссылку на локальную переменную правильно

QString createString() 
{ 
    return QString("foobar"); 
} 

const QString& getString() 
{ 
    return createString(); 
} 

Это даст знаменитый «предупреждение C4172: обратный адрес локальной переменной или временный» с VS2013.

Теперь, если я изменил второй метод

const QString& getString() 
{ 
    const QString& binder = createString(); 
    return binder; 
} 

Который не сообщает об ошибке больше. Это безопасный способ исправить предупреждение без изменения подписи API? Почему это работает?

+0

Почему бы не создать 'createString()' просто вернуть указатель из 'new QString'? Затем вызывающая сторона владеет строкой и может сохранять, удалять или ссылаться на нее по мере необходимости. – donjuedo

+3

@donjuedo Это ужасная идея. Нет никаких указателей, и ручное управление памятью в такой ситуации совершенно необоснованно. – pmr

+0

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

ответ

7

Не работает. Таким образом, вы просто подавляете предупреждение, делая ситуацию сложнее анализировать. Поведение все еще не определено.

+0

Есть ли способ заставить его работать без изменения подписи методов? – x29a

+1

@ x29a: Вы должны привязать ссылку к чему-то нелокальному и не временному.Если у вас есть что-то нелокальное и не временное, которое будет работать для этой цели, тогда используйте его. Некачественным быстрым исправлением было бы использование внутренней переменной 'static' типа' QString'. Но возврат ссылки на независимо проживающую нелокальную и не временную сущность обычно делает функцию непереводимой, что тоже нехорошо. – AnT

+1

Я предполагаю, что метод должен вернуть копию. Благодаря! – x29a

1

Это поведение не определено.

const QString& getString() 
    { 
     const QString& binder = createString(); 
     return binder; 
    } 

После binder выходит за рамки. Он больше не определен. Вы можете определить это, сохранив связывание.

+0

обратите внимание, что его 'createString()' возвращает 'QString', а не' QString & ' – donjuedo

2

Ваше «исправление» - нет.

Чтобы сохранить подпись, вы должны сделать некоторые компромиссы. Как минимум, getString не является реентерабельным, и это невозможно зафиксировать, кроме как вернуть копию строки. Он также не является потокобезопасным, хотя он может быть исправлен без изменения подписи.

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

const QString & getString() { 
    static QString string = createString(); 
    return string; 
} 

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

class Foo { 
    QString m_getString_result; 
public: 
    const QString & getString() { 
    m_getString_result = createString(); 
    return m_getString_result; 
    } 
}; 

Для безопасности потока, вам нужно чтобы сохранить результат в локальном хранилище потоков. Это все равно не исправит проблему повторного входа - как таковая, она не может быть исправлена ​​с учетом вашей подписи.

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