将一个std::字符串复制到另一个时出现段错误

Segfault on copying one std::string to another?

本文关键字:段错误 另一个 错误 字符串 一个 std 复制      更新时间:2023-10-16

我有以下类:

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 FileIon", __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 FileIon", __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应该给出一个segFault,而实现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())
    {
    }
};
相关文章: