1

私は次のクラスを持っています:

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 は segFault を与えるべきであり、実装 2 はすべきではありません。しかし、逆のことが起こっています。理由がわかりません。

後でデストラクタでファイルを削除できるように、クラス メンバとして tempPath 文字列が必要です。

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

あちこちの行をコメントアウトした後、次の行でseg-faultが発生することがわかりました。

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

1 に答える 1

1

2 番目の実装は、オブジェクトが完全に初期化される前に、呼び出し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())
    {
    }
};
于 2013-04-06T15:14:01.353 に答える