【问题标题】:C++ vector of objects of custom class - copy constructor deleted - std::ifstream自定义类对象的 C++ 向量 - 已删除复制构造函数 - std::ifstream
【发布时间】:2019-09-21 17:56:22
【问题描述】:

我正在尝试创建自定义类 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();
    }
};

我主要是用一个 for 循环迭代文件名向量的 A 类的 n 个对象。

例子:

#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&amp;)’

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

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

感谢您的帮助

【问题讨论】:

  • 您的代码由于其他原因无法编译。一个是你在filesList 上调用emplace_backfileList 的拼写错误),而你应该在AList 上调用它。您需要给我们一个完全重现问题的最小示例。
  • 谢谢。为了重现错误,我添加了更多正确的代码。

标签: c++ c++11 vector copy-constructor ifstream


【解决方案1】:

就像你说的,你的 A 类是不可复制的,因为 ifstream 成员不能被复制。所以你的类的复制构造函数默认被删除。 但是当您将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)
{
}

【讨论】:

  • 谢谢,但我得到了同样的错误。 /usr/include/c++/9.1.0/bits/stl_construct.h:75:7: error: use of deleted function ‘A::A(const A&amp;)’ 75 | { ::new(static_cast&lt;void*&gt;(__p)) _T1(std::forward&lt;_Args&gt;(__args)...); } | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~我试过这个代码:int main() { std::vector&lt;A&gt; AList; std::vector&lt;std::string&gt; fileList = { "file1", "file2", "file3" }; for (auto &amp;f : fileList) { std::cout &lt;&lt; f &lt;&lt; std::endl; AList.emplace_back(f); } return 0; }
  • C++ vector emplace_back calls copy constructor。向您的类添加一个移动构造函数以修复错误,如 gimme_danger 的回答所示
【解决方案2】:

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

但是std::ifstream 是可移动的,通常你的类也是可移动的,但是提供自定义析构函数可以防止隐式生成移动构造函数和移动赋值运算符(参见图表 @ 987654321@).

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

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

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

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

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

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

AList.emplace_back(f);

【讨论】:

    【解决方案3】:

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

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

    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));    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-17
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多