这是一项家庭作业。 Field容器是一周前的赋值,现在我应该使用Field容器作为结构NumPair的动态数组,它包含两个char *
,如下所示:
struct NumPair
{
char *pFirst, *pSecond;
int count;
NumPair( char *pfirst = "", char *psecond = "", int count = 0)
: pFirst(strdup(pfirst)), pSecond(strdup(psecond)), count(count)
{ }
NumPair( const NumPair& np )
: count(np.count), pFirst(strdup(np.pFirst)), pSecond(strdup(np.pSecond))
{ }
NumPair& operator=( const NumPair& np )
{
if(this != &np)
{
pFirst = strdup(np.pFirst);
pSecond = strdup(np.pSecond);
count = np.count;
}
return *this;
}
和Field容器
Field<NumPair> dict_;
家庭作业需要使用char *
,而不是字符串,以便我们可以通过所有这些低级别的东西变得更好。我已经对char到wchar_t转换等问题提出了一些问题。
现在我有一个问题是我是否正确地破坏了NumPair。方案如下:
1)字段析构函数被调用
template <class T>
Field<T>::~Field()
{
delete[] v_;
}
2)删除调用v _;
中每个元素NumPair的析构函数~NumPair()
{
free(pFirst);
free(pSecond);
}
这可以吗?我还没有真正阅读太多关于混合和匹配在堆和自由存储上创建的元素的文章。我认为,只要我不对不正确的malloc元素使用删除,我应该没事。
但是,我不知道删除命令的全部错综复杂,所以我想知道这是否是有效的设计,以及我可以做些什么来使它更好。
当然,事实并非如此。我收到了类型错误:
This may be due to a corruption of the heap
并指向dbgheap
extern "C" _CRTIMP int __cdecl _CrtIsValidHeapPointer(
const void * pUserData
)
{
if (!pUserData)
return FALSE;
if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), FALSE))
return FALSE;
return HeapValidate( _crtheap, 0, pHdr(pUserData) ); // Here
}
同样,如何在不使用字符串的情况下改善这一点?
FIELD CTOR / Copy Ctor / Assignment
template <class T>
Field<T>::Field()
: v_(0), vused_(0), vsize_(0)
{ }
template <class T>
Field<T>::Field(size_t n, const T &val)
: v_(0), vused_(n), vsize_(0)
{
if(n > 0)
{
vsize_ = 1;
while(vsize_ < n)
vsize_ <<= 1;
v_ = new T[vsize_];
std::fill(v_, (v_ + vused_), val);
}
}
template <class T>
Field<T>::Field(const Field<T> &other)
: v_(new T[other.vsize_]), vsize_(other.vsize_), vused_(other.vused_)
{
std::copy(other.v_, (other.v_ + other.vused_), v_);
}
template <class T>
Field<T>& Field<T>::operator =(const Field<T> &other)
{
this->v_ = other.v_;
this->vused_ = other.vused_;
this->vsize_ = other.vsize_;
return *this;
}
现场成员
T *v_;
size_t vsize_;
size_t vused_;
答案 0 :(得分:1)
你在NumPair中的字符串处理看起来没问题(strdup + free)你的Field容器delete []看起来没问题,但很难说因为你没有显示v_是什么。
在评论中提到您还应该注意如何复制NumPairs。默认情况下,C ++将为您提供隐式的成员方式复制构造函数。这就是像std :: string这样的RAII类型让你的生活更轻松的地方:你的std :: string包含结构可以复制而不需要你的任何特殊处理,字符串中引用的内存将由字符串来处理复制。如果您复制NumPair(例如通过分配它或从函数返回它),那么临时的销毁将使你的字符串从你的下方释放出来。
答案 1 :(得分:1)
Field的复制构造函数只是复制v_中的指针。如果你有一个Field的两个副本,当第一个Field超出范围时,将删除v_中的所有NumPairs,然后当第二个Field删除时再删除。
答案 2 :(得分:1)
您的复制构造函数(字段&lt;&gt;)似乎没问题,但operator=
存在问题。
它不仅泄漏内存(原始v_
会发生什么?),但在此之后,Field&lt;&gt;的两个实例保持指向同一块内存的指针,并且首先被破坏的那个将使其他的v_
无效 - 你甚至无法判断是否发生了这种情况。
决定如何处理operator=
并不总是那么容易 - 有些人认为隐式移动语义是可以接受的,但我们其他人都会看到这与大多数人一起发挥作用,std::auto_ptr
。可能最简单的解决方案是完全禁用复制,并使用显式函数来移动所有权。