Возврат указателя из метода

241
30 января 2019, 19:50
#include <iostream>
using namespace std;
class B {
public:
    void invoke(){
        cout << "invoke";
    }
};
class A{
public:
    B* test(){
        B b;
        auto *bb = &b;
        return bb;
    }
};
int main() {
    A a;
    B *b = a.test();
    b->invoke();
    b->invoke();
    return 0;
}

Несколько вопросов по этому коду:

  1. будет ли он корректен?
  2. почему компилятор не ругается на return bb;
  3. почему этот код работает, ведь auto *bb локальная переменная(stack) и должна умереть со всеми вместе когда работа метода закончится (return)
Answer 1
  1. Что такое "корректен"? Не содержит диагностируемых ошибок компиляции? Да, с этой точки зрения код "корректен".

    Однако он порождает неопределенное поведение из-за того, что оператор -> выполняет разадресование (indirection) возвращенного a.test() указателя с невалидным значением (invalid pointer value).

  2. А почему он должен ругаться? Никаких нарушений, которые компилятор обязан диагностировать (согласно требованиям спецификации языка), в этом return bb; нет.

    Стоит однако помнить, что неопределенное поведение может выражаться и в отказе компилятора компилировать код программы.

  3. Этот код не "работает". Он порождает неопределенное поведение.
Answer 2

Нет, не будет. Хотя работать будет :)

  1. Возврат указателя на локальную переменную некорректен.

  2. Наверное, уровень warning'ов недостаточный... Visual C++ 2017 при /W4 ругается - "возвращение адреса локальной или временной переменной".

  3. В вызове invoke() никак не используется указатель на объект, поэтому ему по барабану, что туда передается, указатель на что... Скорее всего, он будет нормально работать - хотя и не обязан (UB).

Примерно так.

Варианты исправления:

B* test()
{
    static B b;
    return &b;
}
B* test()
{
    return new B;
}

Первый вариант плох тем, что всегда возвращает один и тот же указатель; второй - тем, что потом нужно не забыть удалить созданный объект. Лучше воспользоваться интеллектуальным указателем типа unique_ptr, который его потом сам уничтожит.

READ ALSO
Преобразование List в другой List

Преобразование List в другой List

Есть две сущности:

296
Проблема с package

Проблема с package

пытаюсь запустить код и компилятор выдает ошибку связанную с package: его не находит

288
Сохранение объектов из Kafka consumer в Postgesql

Сохранение объектов из Kafka consumer в Postgesql

Есть Java приложение с Kafka consumer, которое принимает объекты из топиковТакже используется схема Avro

227
Проверить выход за границы массива по принципу DRY

Проверить выход за границы массива по принципу DRY

Есть массив int[] mas = new mas[size]Существует несколько методов:

259