我有以下课程:
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);
答案 0 :(得分:1)
您的第二个实现调用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())
{
}
};