在销毁派生的std::basic_ostream时出现分段错误

Segmentation fault when destructing a derived std::basic_ostream

本文关键字:ostream 错误 分段 basic 派生 std      更新时间:2023-10-16

我是从std::basic_ostream派生的,因为我需要改变底层文件缓冲区的创建方式。(我需要一个唯一的文件名,我可以查询,以便文件可以在关闭时删除;即不能使用std::tmpnamstd::tmpfile。)我已经尝试过了(见下文),但是我在销毁时遇到了分割错误。

什么原因导致分割错误?似乎我没有为文件缓冲区分配内存,或者我删除了它两次。

// Compile with
//      clang++ -std=c++14 -stdlib=libc++ main.cpp  -o tmpFile
//
#include <iostream>
#include <fstream>
#include <string>
#include <streambuf>
using namespace std;
template< class charT, class traits=char_traits<charT> >
class FILE_streambuf : public std::basic_streambuf<charT, traits> {
public:
    FILE_streambuf(std::string& filename)
    {
      filename = "chicken";
      buffer_ = fopen(filename.c_str(), "wx");
    }
    virtual ~FILE_streambuf(){
        fclose(this->buffer_);
    }
    FILE* buffer_;
};
template< class charT, class traits=char_traits<charT> >
class tmp_ofstream : public basic_ostream<charT, traits>{
public:
    tmp_ofstream()
    : filename_("")
    {
        try{
            this->rdbuf(new FILE_streambuf<charT, traits>(filename_));
        } catch (const std::exception& e){
            throw e;
        }
    }
    ~tmp_ofstream(){
        delete this->rdbuf();
        remove( filename_.c_str() );
    }
    std::string filename() { return this->filename_; };
    std::string filename_;
};
int main(){
    tmp_ofstream<char> tmpStream;
    cout << "tmpStream has filename: " << tmpStream.filename();
    cout << "n-----------------------------------------n";
    return 0;
}

正如Igor Tandetnik所指出的那样,代码隐式调用std::basic_ostream的默认构造函数,该构造函数不应该存在。代码使用libc++编译,因为后者提供了这样一个(受保护的)默认构造函数作为扩展:

basic_ostream() {}  // extension, intentially does not initialize

如果tmp_ofstream的构造函数调用std::basic_ostream的标准认可构造函数,问题就消失了:

tmp_ofstream()
: basic_ostream<charT, traits>(0) // Sic!
, filename_("")
{
    try{
        this->rdbuf(new FILE_streambuf<charT, traits>(filename_));
    } catch (const std::exception& e){
        throw e;
    }
}
相关文章: