Is there a way to make a moved object “invalid”?

Refresh

December 2018

Views

143 time

2

I've some code that moves an object into another object. I won't need the original, moved object anymore in the upper level. Thus move is the right choice I think.

However, thinking about safety I wonder if there is a way to invalidate the moved object and thus preventing undefined behaviour if someone accesses it.

Here is a nice example:

// 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;
}

The description says:

The first call to myvector.push_back copies the value of foo into the vector (foo keeps the value it had before the call). The second call moves the value of bar into the vector. This transfers its content into the vector (while bar loses its value, and now is in a valid but unspecified state).

Is there a way to invalidate bar, such that access to it will cause a compiler error? Something like:

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

Edit: And if there is no such thing, why?

3 answers

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);
}
1

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

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

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

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

0

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

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

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

Изменить: пример 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;
    }
}