2015-10-11 3 views
2

У меня есть код, который перемещает объект в другой объект. Мне больше не понадобится исходный, перемещенный объект на верхнем уровне. Таким образом, движение - правильный выбор, я думаю.Есть ли способ сделать перемещенный объект «недействительным»?

Однако, думая о безопасности, я задаюсь вопросом, есть ли способ сделать недействительным перемещенный объект и тем самым предотвратить неопределенное поведение, если кто-то обратится к нему.

Here хороший пример:

// move example 
#include <utility>  // std::move 
#include <vector>  // std::vector 
#include <string>  // std::string 

int main() { 
    std::string foo = "foo-string"; 
    std::string bar = "bar-string"; 
    std::vector<std::string> myvector; 

    myvector.push_back (foo);     // copies 
    myvector.push_back (std::move(bar));   // moves 

    return 0; 
} 

Описание говорит:

Первый вызов myvector.push_back копирует значение foo в вектор (foo сохраняет значение, которое было до того, как вызов). Второй вызов перемещает значение bar в вектор. Это переносит его содержимое в вектор (в то время как bar теряет свое значение и теперь находится в действительном, но неуказанном состоянии).

Есть ли способ аннулировать bar, так что доступ к нему приведет к ошибке компилятора? Что-то вроде:

myvector.push_back (std::move(bar));   // moves 
invalidate(bar); //something like bar.end() will then result in a compiler error 

Edit: А если нет такой вещи, почему?

ответ

0

Перемещение семантики работает так, чтобы вы получили объект в любом это правильное состояние. Правильное состояние означает, что все поля имеют правильное значение, и все внутренние инварианты по-прежнему хороши. Это было сделано, потому что после перемещения вы фактически не заботитесь о содержимом перемещенного объекта, но такие вещи, как управление ресурсами, назначения и деструкторы должны работать нормально. Все классы STL (и все классы с конструктором/назначением по умолчанию) просто заменяют его содержимым новым, поэтому оба состояния правильные, и их очень легко реализовать, быстро и достаточно удобно.

Вы можете определить свой класс, который имеет поле isValid, которое обычно истинно и перемещается (то есть в перемещение конструктора/перемещение) устанавливает значение false. Тогда ваш объект будет иметь правильно состояние Я инвалид. Просто не забудьте проверить его там, где это необходимо (деструктор, назначение и т. Д.).

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

Edit: пример String:

class String { 
public: 
    string data; 
private: 
    bool m_isValid; 

public: 
    String(string const& b): data(b.data), isValid(true) {} 

    String(String &&b): data(move(b.data)) { 
     b.m_isValid = false; 
    } 

    String const& operator =(String &&b) { 
     data = move(b.data); 
     b.m_isValid = false; 
     return &this; 
    } 

    bool isValid() { 
     return m_isValid; 
    } 
} 
1

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

template< typename T > 
void swap_by_move(T &a, T &b) 
{ 
    using std::move; 
    T c = move(b); 
    b = move(a); 
    a = move(c); 
} 
+0

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

1

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

foo(bar); // foo might move or not 
bar.baz(); // compile time error or not? 

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

Чтобы выразить это по-другому, вы спрашиваете о наличии ошибки времени компиляции, если вы используете целочисленную переменную, которая содержит значение 42. Или если вы используете указатель, который содержит значение нулевого указателя. Возможно, вы преуспели в реализации приблизительного контрольного соглашения о согласовании кода сборки, используя clang API анализа, однако, работая над CFG C++ AST и вызывая ошибку, если вы не можете доказать, что std::move не был вызван до определенного использования Переменная.

Смежные вопросы