c++ - 将一个 std::string 复制到另一个时出现段错误?

标签 c++ oop class scope segmentation-fault

我有以下类(class):

class StdinIo : public FileIo{
    public:
             StdinIo();
             ~StdinIo();

             static StdinIo* createObj(const std::string&);
             static bool     checkPath(const std::string&);
    private:
             std::string     tempPath;
             std::string     newPath();
};  

实现 1:

StdinIo::StdinIo()
        :FileIo(newPath())
{    
}    
std::string StdinIo::newPath(){
        printf("%s Using FileIo\n", __PRETTY_FUNCTION__);
        std::stringstream tempPathStream;

        tempPathStream << tmpnam(NULL) << getpid();

        tempPathStream.flush();
        const char* szTempPath = tempPathStream.str().c_str();

        FILE *fp=fopen(szTempPath,"wb");
        size_t rv=1;
        char buffer[1024*8];
        if(fp){
                while(rv){
                        rv=fread(buffer,1,sizeof(buffer),stdin);
                        fwrite(buffer,1,rv,fp);
                }
                fclose(fp);
        }
        return tempPathStream.str();
}    

实现 2:

StdinIo::StdinIo()
        :FileIo(newPath())
{    
}    
std::string StdinIo::newPath(){
        printf("%s Using FileIo\n", __PRETTY_FUNCTION__);
        std::stringstream tempPathStream;

        tempPathStream << tmpnam(NULL) << getpid();

        tempPathStream.flush();
        tempPath = tempPathStream.str();
        const char* szTempPath = tempPath.c_str();

        FILE *fp=fopen(szTempPath,"wb");
        size_t rv=1;
        char buffer[1024*8];
        if(fp){
                while(rv){
                        rv=fread(buffer,1,sizeof(buffer),stdin);
                        fwrite(buffer,1,rv,fp);
                }
                fclose(fp);
        }
        return tempPath;
  }    

根据我对堆栈的了解,实现 1 应该给出段错误,而实现 2 不应该。但相反的情况正在发生。我不知道为什么。

我需要 tempPath 字符串作为类成员,以便稍后在析构函数中删除文件。

StdinIo::~StdinIo(){
      if( unlink(tempPath.c_str()) != 0 )
              perror( "Error deleting file" );
}

注释掉这里那里的行后,我发现在下面的行中,发生了段错误:

 tempPath = tempPathStream.str();

gdb 说:

 Program received signal SIGSEGV, Segmentation fault.
 __exchange_and_add_dispatch (__mem=0xfffffffffffffff8, __val=<optimized out>)
     at /usr/src/debug/gcc-4.7.2-20120921/obj-x86_64-redhat-linux/x86_64-redhat-          linux/libstdc++-v3/include/ext/atomicity.h:83
 83       return __exchange_and_add_single(__mem, __val);

最佳答案

在对象完全初始化之前,您的第二个实现调用 newPath() 并访问 tempPath(将其传递给基类构造函数)。这会导致未定义的行为。

如果您绝对需要文件名的本地拷贝而不会对现有代码进行重大更改,您可以使用实现 #1 来实现类似的东西。

class StdIoSpecialData : public FileIo
{
protected:

    StdIoSpecialData(const std::string &fname)
        : FileIo(fname),
          tempPath(fname)
    {
    }
    const std::string tempPath;
};

class StdIo : public StdIoSpecialData
{
public:
    StdIo()
       : StdIoSpecialData(newPath())
    {
    }
};

关于c++ - 将一个 std::string 复制到另一个时出现段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15852459/

相关文章:

c# - 参数过多的构造函数

java - 在反射中,方法对象的参数类与参数类不匹配?

c++ - 类局部特化继承方法

c# - 为什么将基类型实例转换为派生类型对象/引用不是类型安全的

c++ - 类模板特化的运算符重载

c++ - 全等、相似和直角三角形

c++ - 为什么 C++ 编译器不区分同名的继承公共(public)方法和继承私有(private)方法?

php - 在其他命名空间中使用多个类

c++ - 使用外部函数进行堆栈推送

c++ - C++11 是否允许引用匿名临时对象