Скопируйте конструктор класса с константным векторным членом - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть класс OpenTable в моем коде:

class OpenTable : public BaseAction {
public:
    OpenTable(int id, std::vector<Customer *> &customersList);
    OpenTable(const OpenTable& other);
private:
    const int tableId;
    const std::vector<Customer *> customers;
};

Мне нужно реализовать конструктор копирования для этого класса (я знаю, что это, вероятно, плохой дизайн, но я получил указание сделать это). Я столкнулся с проблемой при попытке глубокого копирования константного вектора customers.

Я попробовал следующее:

OpenTable::OpenTable(const OpenTable& other): tableId(other.tableId)
{
    for(std::vector<Customer*>::const_iterator i=other.customers.begin(); i!=other.customers.end(); i++) {
         customers.push_back((*i)->copy()); // copy returns a Customer*
    }

Но, очевидно, он не компилируется, вероятно, потому что вектор const, поэтому я не могу добавить к нему элементы.

Я получаю следующую ошибку:

no instance of overloaded function "std::vector<_Tp, _Alloc>::push_back 
[with _Tp=Customer *, _Alloc=std::allocator<Customer *>]" matches the 
argument list and object (the object has type qualifiers that prevent a 
match) -- argument types are: (Customer *) -- object type is: const 
std::vector<Customer *, std::allocator<Customer *>>

Примечание: в параметризованном конструкторе я просто копировал, потому что мог. Это не будет работать для конструктора копирования.

Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Почему вы используете члены класса const? Вы не можете ничего с ними поделать. Вместо этого сделайте функции публичного доступа доступными только для чтения.

std::vector<Customers *> const getCustumers() const { return customers;}
int const getTableId() const { return tableId; }

Это даст вам вектор клиентов только для чтения или идентификатор таблицы, который нельзя изменить. С копией конструктора проблем нет.

0 голосов
/ 09 ноября 2018

Самое простое решение - создать вспомогательную функцию, которая принимает const std::vector<Customer *> и возвращает std::vector<Customer *>, которая является глубокой копией аргумента. Затем в списке инициализатора вашего конструктора используйте эту функцию для инициализации вашего частного члена.

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

Если возникает проблема в вспомогательной функции, выполняющей глубокое копирование, вспомогательную функцию необходимо будет очистить соответствующим образом (например, если создание одного из объектов Customer завершится неудачно, все успешно построенные объекты необходимо будет освободить, чтобы избежать утечка памяти).

0 голосов
/ 08 ноября 2018

Вам понадобится что-то вроде boost::transform_iterator, чтобы выполнить копирование как часть инициализатора элемента.

auto copy_iter(auto iter)
{
    return boost::make_transform_iterator(iter, [](Customer * c){ return c->copy(); });
}

OpenTable::OpenTable(const OpenTable& other)
 : tableId(other.tableId),
   customers(copy_iter(other.customers.begin()), copy_iter(other.customers.end()))
{}

или поочередно

OpenTable::OpenTable(const OpenTable& other)
 : tableId(other.tableId),
   customers(boost::copy_range<std::vector<Customer *>>(other.customers | boost::adaptors::transformed([](Customer * c){ return c->copy(); })))
{}
...