Как использовать std :: vector для классов с дескрипторами - PullRequest
3 голосов
/ 22 мая 2019

Я определил следующий класс, который создает и освобождает непрозрачный объект (например, дескриптор операционной системы)

class A
{
public:

    A(...)
    {
        allocateHandle(&h);
    }

    ~A()
    {
        freeHandle(h);
    }

    SomeHandle h;
}

При создании и изменении размера std :: vector of A программа вылетает.

std::vector<A> vec;
vec.reserve(2);

vec.emplace_back(...);
vec.emplace_back(...);
vec.emplace_back(...); //crash

Когда std :: vector перераспределяет память, он вызывает конструктор перемещения для всех объектов, таким образом, также перемещая дескриптор в A (который в основном является целым числом).

Однако он также вызываетдеструктор на старом объекте, который вызывает freeHandle(), таким образом он освобождает память за дескриптором, что новый объект все еще имеет, который становится недействительным и вызывает сбой.

Как мне реализовать move-конструктор, чтобы вновь созданный объект не становился недействительным при удалении старого?

1 Ответ

8 голосов
/ 22 мая 2019

Вам необходимо добавить в ваши объекты состояние "не удерживается допустимая ручка".Если ваш SomeHandle уже имеет значение «недопустимый дескриптор» (довольно часто для этого используется 0), вы можете использовать это:

class A
{
public:

    A(...)
    {
        allocateHandle(&h);
    }

    A(A &&src) : h(src.h)
    {
        src.h = INVALID;
    }

    A& operator= (A &&rhs)
    {
      if (this == &rhs) return *this;
      if (h != INVALID) freeHandle(h);
      h = rhs.h;
      rhs.h = INVALID;
      return *this;
    }

    ~A()
    {
        if (h != INVALID)
          freeHandle(h);
    }

    SomeHandle h;
}

Если значения «недопустимый дескриптор» нет, вы можетеизмените тип h на std::optional<SomeHandle> и используйте std::nullopt в качестве недопустимого значения.

...