C ++ 0x: когда временный объект равен другому временному объекту - PullRequest
0 голосов
/ 02 февраля 2012
struct F
{
private:
    int* data;

public:
    F( int n ) 
    { 
        data = new int; 
        *data = n; 
    }

    F( int* p ) 
    { 
        data = p; 
    }

    F& operator=( const F& f ) 
    { 
        *data = *(f.get_data()); 
        return *this; 
    }

    F& operator=( F&& f ) 
    {
        delete data;
        data = f.data;
        f.data = nullptr;
        return *this;
    }

    F& operator=( int n ) { *data = n; return *this; }

    F operator()() 
    {
        F cpy_f( data );
        return std::move( cpy_f );
    }

    int* get_data() const { return data; }
};

int main()
{
    F f( 12 );
    F g( 14 );
    f() = g();
    cout << *(f.get_data()) << endl;
}

В этом примере f() и g() соответственно возвращают временный объект, поэтому f()=g() приводит к выражению временного объекта, равного временному объекту . Я бы ожидал, что ответ 14, если значение правильно скопировано. Тем не менее, НЕ вызывает копирование , НО , вызывая перемещение ! В результате ответ не 14.

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

пс. Мой компилятор g ++ 4.7 20110430

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Ваш operator() возвращает значение, а не ссылку или указатель.Поэтому он возвращает временный.Временные неявно привязываются к && преимущественно (это единственные типы, которые делают это)Поэтому, если для них есть оператор присваивания перемещения, они предпочтут его использовать.

Ваша проблема в том, что вы перестали делать разумные вещи, когда сделали это в своей функции operator():

F cpy_f( data );

Конструктор F, который принимает указатель, использует само значение указателя, эффективно применяя указатель.В этот момент у вас теперь есть два F экземпляра, которые указывают на одни и те же данные.

Если вы хотите быть разумными, то вы не можете иметьВаш оператор назначения перемещения удаляет указатель.Вам нужно согласовать тот факт, что у вас может быть два F экземпляра, которые указывают на одно и то же.Эти два должны разделить владение указателем.Итак ... как вы планируете это сделать?

Я бы предложил полностью избавиться от этого конструктора.Это только создаст вам больше проблем.Я бы также предложил использовать std::unique_ptr<int> data; вместо голого указателя.Таким образом, вам не нужно писать конструктор перемещения / оператор присваивания (хотя вам действительно нужен конструктор копирования / оператор присваивания).

0 голосов
/ 02 февраля 2012

Вы создаете экземпляр, указатель которого указывает на то же место. Экземпляр, созданный с помощью F::operator(), не совместно использует сам указатель.

f()=g() эквивалентно f (). Operator = (g ()), а g() создает временный экземпляр, поэтому правильно вызывать назначение перемещения.

Проблема в том, что f имеет висячий указатель после выполнения f()=g(). f() создает временный экземпляр, он удаляет указатель в операторе присваивания перемещения, но сам f все еще имеет указатель, который указывает на удаленное местоположение.

Я не уверен, что вы делаете с этим сложным кодом, но вам лучше переписать код с std::shared_ptr или чем-то еще.

p.s. Вам не нужно std::move при возврате экземпляра. Ваш компилятор имеет функции RVO, если вы не отключили их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...