Вопрос о точном времени уничтожения временных файлов в C ++ - PullRequest
3 голосов
/ 25 февраля 2010

- это следующий безопасный код (работает в DEBUG):

void takesPointer(const Type* v);//this function does read from v, it doesn't alter v in any way
Type getValue();
...
takesPointer(&getValue());//gives warning while compiling "not an lvalue"
...
Type tmp = getValue();
takesPointer(&tmp);//this is safe, and maybe I should just do it, instead of posting here

так - это безопасно? Должен ли я просто забыть об этом и использовать код с явным tmp?

но в любом случае - мне все еще интересно, разрешено ли оптимизатору уничтожить временное хранилище перед возвратом из этого вызова:

takePointer(&getValue())

EDIT: Спасибо вам всем ! К сожалению, я не могу изменить функцию «takePointer» (это часть библиотеки), я могу только обернуть ее в функцию «takeReoference», которая вызывает takePointer - это исключит копию, или компилятору все равно будет разрешено копия («Тип» - это матрица типа int-3x3, так что это было бы НЕ ТАК плохо, но все же ...)?

inline void takesReference(const Type& v){ takesPointer(&v); }

О времени уничтожения: будет ли оно уничтожено после ВОЗВРАТА «takePointer» или после того, как оно ВЫЗВАНО?

Ответы [ 5 ]

10 голосов
/ 25 февраля 2010

Как уже говорилось в других ответах, вы не можете получить временный адрес. Однако, если вы измените подпись

void takesPointer(const Type* v);

до

void takesPointer(const Type& v);

тогда следующий код должен компилироваться без предупреждений:

takesPointer(getValue());

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

7 голосов
/ 25 февраля 2010

Стандарт запрещает вам делать &getValue() - именно потому, что это не lvalue. Обычно, если это было разрешено , то временный результат, вызванный этим вызовом функции, будет действовать до тех пор, пока не вернется внешняя функция, и все остальные элементы во всем выражении не будут обработаны. Это можно назвать «уничтожением временных объектов после завершения полного выражения» и гарантирует, что такие вещи, как следующие, будут работать, как и ожидалось

// the temporary string is alive until the whole expression has been processed
cout << string("hello");

Компилятор дает вам диагностику - это все, что требует стандарт для некорректного кода. Например, это не заставляет компилятор прерывать компиляцию. Но после того, как код был неправильно сформирован, компилятор может делать все, что захочет. Так что если вы хотите знать, что делает компилятор в вашем случае, вам следует прочитать его руководство.

1 голос
/ 25 февраля 2010

Это предотвратит копирование * и компиляцию.

const Type& tmp = getValue(); 
takesPointer(&tmp);

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

#include "iostream"
class Type
{
public:
    explicit Type(int val) : m_val(val) { std::cout << "ctor";};
    Type(const Type& copy)
    {
        std::cout << "copy";
    };
private:
    int m_val;
};

Type getValue() { Type r(0); return r;};
void takesPointer(const Type* const)
{

};

int main(int argc, char* argv[])
{
    const Type tmp = getValue(); 
    takesPointer(&tmp);
}

Будет печатать только "ctor" в выпуске и "ctorcopy" в отладке. (MVS2005)

0 голосов
/ 25 февраля 2010

Да, это безопасно, хотя и незаконно в текущей форме. Вы можете обойти ошибку, используя явное промежуточное приведение к типу const-reference

takesPointer( &(const Type &) getValue() );

Это делает его совершенно законным, пока временный объект жив, то есть до конца оценки полного выражения.

Более того, вы даже можете выбросить константу и изменить временный объект с помощью указателя (помните, что он будет уничтожен в конце полного выражения). Это совершенно законно, пока сам временный объект не является постоянным.

Используя оператор запятой, вы можете «растянуть» полные выражения и таким образом написать довольно обширные последовательности операций, которые работают с «долгоживущим» временным объектом

Type *p;
p = &(Type &) (const Type &) getValue(), modify(p), print(p), modifyAgain(p), print(p);
// Not using C++ casts for brevity

Практика довольно сомнительна, и в большинстве случаев это бессмысленно.

0 голосов
/ 25 февраля 2010

Вам разрешено привязывать неконстантное значение к константной ссылке lvalue, но вы привязываете его к константному указателю lvalue.

И нет, оптимизатор не может уничтожить результат getValue() перед вызовом takePointer().

...