Конструктор копирования и целостность указателей

Рейтинг: 1Ответов: 2Опубликовано: 08.01.2015

У меня есть класс Stream, одним из членов которого является вектор объектов класса Request. Элементы вектора создаются в конструкторе класса Stream, причем одним из полей класса Request является указатель на родительский объект класса Stream. При копировании объектов класса Stream указатели в объектах Request "ломаются": они почему-то указывают на объекты Stream, в которых вектор объектов Request пуст. Насколько я понимаю, это происходит потому, что стандартный конструктор копирования не заботится о сохранности указателей. Как написать свой конструктор копирования, в котором внутри вызывается стандартный конструктор копирования (чтобы не писать код присвоения каждого члена)? Или как иначе можно решить проблему сохранности указателей?

Ответы

▲ 3Принят

Исходя из названия, вам не нужен конструктор копирования. Копировать Stream обычно не имеет смысла, так как это скорее всего приведёт к хаосу при попытке писать в поток из двух экземпляров.

Наоборот, вам нужно запретить копирование. Для этого в свежих версиях компилятора просто допишите внутри класса

Stream(const Stream&) = delete;

Если вы всё же хотите построить копирующий конструктор, вам нужно, по идее, просто скопировать вектор:

class Stream
{
    vector<Request> requests;
public:
    Stream(const Stream& s) : requests(s.requests)
    {
    }
};

Но! Чтобы это правильно работало, у вас обязан быть правильный конструктор копирования в Request.


Если новые Request-объекты должны знать о новом Stream, вам придётся поизвращаться:

class Stream
{
    vector<Request> requests;
public:
    Stream(const Stream& s) :
        requests(s.requests.size()) // выделяем место, не копируем
    {
        for (auto& req : s.requests)
            requests.emplace_back(Request(req, this));
            // создаём новые реквесты, указывающие на *этот* стрим
    }
};

Если я не ошибаюсь, можно опустить Request в emplace_back:

            requests.emplace_back(req, this);

Будет вызван соответствующий конструктор.

▲ 1

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


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

Просто до безобразия. Добавьте к структуре данных дополнительный базовый класс (base), члены которого должны быть скопированы автоматически. В наследуемом от базового (derivative) оставьте члены, копирование которых должно быть под контролем. После этого в констукторе можно дописать в список инициализации:

derivative( const derivative&src ) : base( src ){
  ...
}

Все члены из базового класса будут скопированы автоматически.

P.S. Аналогично задача решается и в операторе присваивания (дополнительным "кастом" this к базовому).