Temporary whose address is used as value of local variable 'pr' will be destroyed at the end of the full-expression (C++)?

Рейтинг: -2Ответов: 2Опубликовано: 12.06.2023

А в чем тут ошибка? Возникла после обновления на версию движка 5.2. Локальная переменная pr будет уничтожена после завершения выражения.

введите сюда описание изображения

введите сюда описание изображения

Ответы

▲ 2Принят

Насколько я понял TCHAR_TO_UTF8 это специальный макрос который освободит выделенную под строку память сразу после ";" поэтому указатель pr окажется висящим. Ошибка возникла вероятнее всего потому что с новой версией добавили больше проверок на подобные ошибки в коде. Использование макросов непосредственно в выражении где используются указатели должно решить проблему.

Об этом говорится в документации:введите сюда описание изображения

▲ 1

Макрос TCHAR_TO_UTF8 создаёт внутри себя объект типа FTCHARToUTF8 и возвращает указатель на внутреннюю память этого объекта:

#define TCHAR_TO_UTF8(str) (ANSICHAR*)FTCHARToUTF8((const TCHAR*)str).Get()

Время жизни анонимного объекта типа FTCHARToUTF8 до конца statement-а. Соответственно, в строке 595 вашего кода этот объект уже не существует, и указатель pr указывает в память с неопределённым содержимым.

Если не использовать временную переменную pr, то ошибка должна исчезнуть:

const chat * getItem = element->Attribute(TCHAR_TO_UTF8(*attrName));

В этом случае временный объект будет существовать до завершения вызова функции, и временный указатель, возвращенный методом Get, будет валиден.

Вот пример висящей ссылки:

#include <iostream>

using namespace std;

class A {
    private:
      int x;
    public:
      A(int x) : x(x) {
        cout << "A(" << x << ")" << endl;
      }
      ~A() {
        cout << "~A(" << x << ")" << endl;
      }
      int* get() { return &x; }
};

class B {
    private:
      int* ptr;
    public:
      B(int* ptr) : ptr(ptr) {
        cout << "B(&" << *ptr << ")" << endl;
      }
      ~B() {
        cout << "~B(&" << *ptr << ")" << endl;
      }
      int* get() { return ptr; }
      int operator * () { return *ptr; }
};

#define Z(x) (A((x)).get())

int main() {
    {
        int x = 42;
        cout << "Before Z" << endl;
        B y = Z(x);
        cout << "After Z" << endl;
        cout << "*y = " << *y << endl;
    }
    cout << "The end!";
    return 0;
}
Before Z
A(42)
B(&42)
~A(42)
After Z
*y = 42
~B(&42)

Внутри макроса Z создаётся объект типа A. Этот объект существует до конца инициализации B y, сразу после инициазации уничтожается. Поэтому y.ptr указывает на уже освобождённую память. В этом примере, вообще говоря, повезло, что память не испортилась.

Если main немного подкрутить, добавив дополнительные переменные, то содержимое y необратимо портится:

int main() {
    {
        int x = 42;
        cout << "Before Z" << endl;
        B y = Z(x);
        cout << "After Z" << endl;
        int zero = 0;
        B b_zero = &zero;
        cout << "*y = " << *y << endl;
        cout << "*b_zero = " << *b_zero << endl;
    }
    cout << "The end!";
    return 0;
}
Before Z
A(42)
B(&42)
~A(42)
After Z
B(&0)
*y = -341712064
*b_zero = 0
~B(&0)
~B(&-341712064)