C ++ вектор объектов пользовательского класса - конструктор копирования удален - std :: ifstream - PullRequest
2 голосов
/ 21 сентября 2019

Я пытаюсь создать вектор объектов пользовательского класса A:

class A {
    std::ifstream _file;
    std::string _fileName;
public:
    A(std::string &fileName) : _fileName(fileName) {
        this->_file = std::ifstream(this->_fileName, std::ios::in);
    }
    ~A() {
        this->_file.close();
    }
};

В основном я помещаю n объектов класса A с циклом for, повторяющим вектор имен файлов.

Пример:

#include <iostream>
#include <string>
#include <vector>
#include "A.hpp"

int main() {

    std::vector<A> AList;
    std::vector<std::string> fileList = { "file1", "file2", "file3" };

    for (auto &f : fileList) {
        std::cout << f << std::endl;
        A tempObj(f);
        AList.emplace_back(tempObj);
    }

    return 0;
}

Но я получаю эту ошибку: /usr/include/c++/9.1.0/bits/stl_construct.h:75:7: error: use of deleted function ‘A::A(const A&)’

Если я не ошибаюсь, так как у меня есть член std :: ifstream внутримой класс А, конструктор копирования удален (Ссылка: https://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream)

Как я могу это решить? Что я делаю не так?

Спасибо за вашу помощь

Ответы [ 3 ]

4 голосов
/ 21 сентября 2019

Как вы сказали, ваш класс A не может быть скопирован из-за члена ifstream, который не может быть скопирован.Таким образом, конструктор копирования вашего класса удаляется по умолчанию.Но вы пытаетесь скопировать-создать объект A, когда передаете tempFile в emplace_back().

. Вместо этого вам нужно передать имя файла emplace_back() и позволить ему создать объект Aвнутри вектора для вас, перенаправив строку в ваш конструктор:

std::vector<A> AList;
std::vector<std::string> fileList;

for (auto &f : fileList)
{
    AList.emplace_back(f);
}

На заметке стороннего конструктора ваш конструктор может и должен инициализировать ifstream в списке инициализации в теле конструктора:

A::A(std::string &fileName)
    : _file(fileName), _fileName(fileName)
{
}
2 голосов
/ 21 сентября 2019

Как отмечалось в другом ответе, class A не подлежит копированию, поскольку его член std::ifstream _file; не подлежит копированию.

Но std::ifstream является подвижным, и обычно ваш класс также будет подвижным, но , предоставляя пользовательский деструктор, предотвращает неявную генерацию конструктора перемещения и оператора назначения перемещения (см. Диаграмму здесь ).

Итак, шаг 1: Создатьваш класс можно перемещать, удаляя пользовательский деструктор (неявно созданный деструктор все равно будет делать то же самое).

В качестве альтернативы, если вы по какой-то причине хотите оставить деструктор, вам нужно попросить компилятор сгенерировать движениеконструктор и оператор присваивания перемещения:

A(A &&) = default;
A &operator=(A &&) = default;

Шаг 2. При добавлении экземпляра class A в вектор переместите его вместо копирования:

A tempObj(f);
AList.emplace_back(std::move(tempObj));
//                 ^^^^^^^^^^       ^

В качестве альтернативы, создайте егопрямо в векторе:

AList.emplace_back(f);
1 голос
/ 21 сентября 2019

Если я не ошибаюсь, так как в моем классе A есть член std :: ifstream, конструктор копирования удаляется (Ссылка: https://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream)

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

A(A&& other) noexcept 
  : _file(move(other._file))
  , _fileName(move(other._fileName))
{}

И теперь ваш код работает отлично , потому что векторные элементы правильно создаются во время нажатия:

std::vector<A> AList;
for (auto &f : { "file1", "file2", "file3" })
  AList.push_back(A(f));    
...