![](/img/trans.png)
[英]Why do I see unusual behavior when using std::vector with a default constructor?
[英]Unusual behavior with std::vector
我编写了一组相当复杂的类来处理迭代流(字符串,文件或内存)。 这些不是标准流,也不是相关的。 无论如何,由于迭代这些缓冲区并根据缓冲区执行操作,我希望能够在调试器中看到当前的缓冲区位置。 因此,仅出于调试原因,我将整个流复制到向量并保持指向此向量中位置的指针。
以下代码的作用类似于前向迭代器。 我需要能够存储一个位置,然后使用它或更新它。 请注意,此代码仅用于复制问题。
class foo
{
public:
foo ( std::string szTemp )
: nOffset( 0 )
{
vec.resize( szTemp.size() );
std::memcpy( &vec[ 0 ], szTemp.c_str(), szTemp.size() );
pChar = &vec[ 0 ];
}
foo( const foo & Other )
: vec( Other.vec )
, nOffset( Other.nOffset )
{
pChar = &vec[ nOffset ];
}
void Inc ( void )
{
++nOffset;
pChar = &vec[ nOffset ];
}
size_t nOffset;
char * pChar;
std::vector< char > vec;
};
int _tmain ( int argc, _TCHAR* argv[] )
{
foo a( "This is a temp string" );
a.Inc();
{
foo b = a;
b.Inc();
a = b;
} // Here is where the problem is seen
a.Inc();
}
问题,在将b复制回到然后踩出之后,b.pChar的值变为非法。
据我了解,b从a复制矢量,然后又从b复制它。 因为我在这个副本之后设置了pChar的值,它应该总是指向某个东西。 但是,它就像矢量被摧毁一样。
这是怎么回事?
{
foo b = a;
b.Inc();
a = b;
} // Here is where the problem is seen
你的问题在这里。
a = b;
请求调用赋值运算符,表示您没有实现,因此,默认值将执行成员赋值。 在此之后,你的char pointer
将是悬空指针。 以下代码将做正确的工作。
class foo
{
public:
foo ( std::string szTemp )
: nOffset( 0 )
{
vec.resize( szTemp.size() );
std::memcpy( &vec[ 0 ], szTemp.c_str(), szTemp.size() );
pChar = &vec[ 0 ];
}
foo( const foo & Other )
: vec( Other.vec )
, nOffset( Other.nOffset )
{
pChar = &vec[ nOffset ];
}
foo& operator = (const foo& other)
{
foo tmp(other);
swap(tmp);
return *this;
}
void Inc ( void )
{
++nOffset;
pChar = &vec[ nOffset ];
}
void Swap(foo& other)
{
std::swap(vec, other.vec);
std::swap(nOffset, other.nOffset);
std::swap(pChar, other.pChar);
}
size_t nOffset;
char * pChar;
std::vector< char > vec;
};
你的班级不遵循三条规则 。 您有自定义复制构造函数,但不是自定义赋值运算符(并且没有自定义析构函数,但此特定类可能不需要它)。 这意味着foo b = a;
做你想要的(称你的副本ctor),但a = b;
没有(调用默认赋值op)。
正如在另外两个答案中所提到的,在他指定a = b
, a.pChar
指向b.vec
,并且由于b
已经离开范围,因此它是一个悬空指针。 您应该遵守三条规则(使用C ++ 11的移动操作的五条规则),或者通过避免存储pChar
使该规则变得不必要,因为这似乎只是offset
的便利别名:
class foo
{
public:
foo ( std::string szTemp )
: nOffset( 0 )
{
vec.resize( szTemp.size() );
std::coyp( begin(szTemp), end(szTemp), begin(vec) );
}
//special members:
foo(foo const&) = default;
foo(foo&&) = default;
foo& operator=(foo const&) = default;
foo& operator=(foo&&) = default;
~foo() = default;
void Inc ( void )
{
++nOffset;
}
char* pChar() //function instead of member variable!
{
return &vec[nOffset];
}
size_t nOffset;
std::vector< char > vec;
};
这样, pChar()
将始终与nOffset
一致,并且特殊成员可以只是默认(或完全省略)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.