C ++: ссылки как возвращаемые значения - PullRequest
2 голосов
/ 15 апреля 2011

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

struct Foo
{
    int x;

    Foo() {
        x = 3;
    }
};

Foo* foo = new Foo;

Foo& test(bool flag) {
    if (flag)
        return *foo;
}

Если test () не (явно) не возвращает значение, я все равно получу что-то возвращенное. Однако возвращаемый объект Foo не инициализируется с помощью конструктора по умолчанию & mdash; это потому, что x отличается от 3 неявным возвращаемым значением.

Что на самом деле происходит, когда вы не возвращаете ссылку? Если это функция, безопасно ли ее использовать в качестве средства для возврата фиктивных объектов в случае возникновения ошибок, в отличие от возврата нулевого указателя. (См. Пример ниже.)

class FooFactory
{
    // Return reference...

    Foo& createFooRef() {
        Foo* foo = new Foo;
        bool success = foo->load();

        if (success)
            return *foo;
        // Implicit (and safe?) return value on failure?
    }

    // ... as opposed to returning a pointer.

    Foo* createFooPtr() {
         Foo* foo = new foo;
         bool success = foo->load();

         if (success)
             return foo;
         else
             return 0;
    }

    // Yes, I am aware of the memory leaks,
    // but that's not the point of the example.

Ответы [ 6 ]

3 голосов
/ 15 апреля 2011

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

Нет, это небезопасно.Это плохо.Это может привести к повреждению стека, просто возвращая то, что в данный момент находится в стеке.Как вы уже видели, он не использует конструктор для вас.Если вам нужен созданный по умолчанию объект, вы должны сделать это самостоятельно (но будьте осторожны, возвращая ссылку на временный объект. Это тоже плохо).

2 голосов
/ 15 апреля 2011

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

2 голосов
/ 15 апреля 2011

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

Формально на языке эффекты не определены.

1 голос
/ 15 апреля 2011

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

Мне пришлось использовать функцию, а затем добавить -Wall, чтобы g ++ пожаловался:

g ++ -Wall foo.cc foo.cc: В функции-члене 'Foo & FooFactory :: createFooRef ()': foo.cc:19: предупреждение: управление достигает конца не пустой функции

1 голос
/ 15 апреля 2011

Описанное поведение не ограничивается функциями, которые возвращают ссылки. Следующий код также будет скомпилирован:
int func1( int i )<br> {<br> if( i )<br> return 3; // C4715 warning, nothing returned if i == 0<br> }
Я не уверен, почему они генерируют только предупреждение , а не ошибку (в настройках может быть опция, превращающая это в ошибку), но вы получите неопределенное поведение, если вызовете такую ​​функцию

0 голосов
/ 15 апреля 2011

Вы пробовали компилировать с оптимизацией / O1 или выше и воспринимать предупреждения как ошибки? Это может потерпеть неудачу. Я помню кое-что подобное в GCC 4.1. Вы можете забыть вернуть ссылку в режиме отладки, но ссылка вернется; как только вы добавите какие-либо оптимизации, он все равно скомпилируется, но не вернет ссылку. При кодировании в текстовом редакторе (как я это делал в те дни) это было полной болью и огромным сюрпризом для меня.

...