不能 push_back 包含指向矢量的 ofstream 指针的 class

Can't push_back a class containing an ofstream pointer to a vector

我在尝试将包含 ofstream 指针的 class 推送到向量时遇到了一个奇怪的段错误。我已将问题缩小到最简单的测试用例:

Test.h

#ifndef __TEST_
#define __TEST_

#include <fstream>
#include <string>

class Test {
public:
    Test(std::string path);
    ~Test();
private:
    ofstream* ofstr;
}

#endif

Test.cpp

#include "Test.h"

Test::Test(std::string path) {
    ofstr = new ofstream(path, std::ios::app);
}

Test::~Test() {
    delete ofstr;
}

main.cpp

#include <vector>
#include "Test.h"

int main() {
    Test test("hello.txt");
    std::vector<Test> vec;
    vec.push_back(test); // segfaults
}

我认为段错误与测试的析构函数有关,但我不确定为什么。当我使用 emplace_back 时也会发生段错误。

您的代码遇到的第一个问题是您没有遵循 The Rule of Three

但是,您的问题比建议遵循三法则的问题更严重。

假设您的 class 有一个与 std::ofstream* 不同的成员变量。

class Test {
  public:
    Test(int in) : ptr(new int(in)) {}
    ~Test();
private:
    int* ptr;
}

您可以通过确保在复制构造函数和复制赋值运算符中做正确的事情来更新 class 以遵循三规则。在这两种情况下,您都必须使用以下内容:

ptr = new int(*copy.ptr);

这适用于大多数类型。但是,这对 std::ofstream 不起作用,因为 std::ofstream 没有复制构造函数或 virtual 可以通过克隆对象 return 指针的函数。

对于您的情况,以下都不是一个选项。

ofstr = new ofstream(*copy.ofstr);
ofstr = copy.ofstr->clone();

要解决该问题,您可以使用 std::shared_ptr<std::ofstream>

class Test {
  public:
    Test(std::string path);
    ~Test();
  private:
    std::shared_ptr<std::ofstream> ofstr;
}

当您这样做时,不仅可以解决您的问题,还可以让编译器生成的析构函数、复制构造函数和复制赋值运算符做正确的事情。您的 class 定义可以简化为:

class Test {
  public:
    Test(std::string path);
  private:
    std::shared_ptr<std::ofstream> ofstr;
}