自定义对象的 C++ 向量 class - 复制构造函数已删除 - std::ifstream

C++ vector of objects of custom class - copy constructor deleted - std::ifstream

我正在尝试创建自定义对象的矢量 class 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();
    }
};

主要是我推送 class A 的 n 个对象,并使用 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&)’

如果我没记错的话,因为我的 class A 中有一个成员 std::ifstream,复制构造函数被删除(参考:https://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream

我该如何解决?我做错了什么?

感谢您的帮助

就像你说的,你的Aclass是不可复制的,因为ifstream成员是不可复制的。所以你的 class 的复制构造函数默认被删除了。 但是当您将 tempFile 传递给 emplace_back().

时,您正试图复制构造一个 A 对象

您需要将文件名传递给 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)
{
}

If I'm not wrong, since I have a member std::ifstream inside my class A, the copy constructor is deleted (Ref: https://en.cppreference.com/w/cpp/io/basic_ifstream/basic_ifstream)

你是对的,std::basic_ifstream是不可复制类型的一个例子,因为一个流有多个副本是不合逻辑的。在这种情况下,您应该使用移动语义。只需将 move constructor 添加到您的 class 定义中:

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

现在您的代码可以工作了 fine,因为向量元素在推送过程中被正确构建:

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

如另一个答案所述,class A 是不可复制的,因为它的成员 std::ifstream _file; 是不可复制的。

但是 std::ifstream 是可移动的,通常您的 class 也是可移动的,但是 提供自定义析构函数可以防止隐式生成移动构造函数和一个移动赋值运算符(见图表)。

因此,第 1 步:通过删除自定义析构函数使您的 class 可移动(隐式生成的析构函数无论如何都会做同样的事情)。

或者,如果出于某种原因要保留析构函数,则需要让编译器生成移动构造函数和移动赋值运算符:

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

第 2 步:将 class A 的实例添加到矢量时,移动它而不是复制它:

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

或者,直接在向量中构造它:

AList.emplace_back(f);