简体   繁体   中英

Am I Deleting my struct Properly?

This is a homework assignment. The Field container was the assignment from a week ago, and now I'm supposed to use the Field container to act as a dynamic array for a struct NumPair which holds two char * like so:

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;
}

and the Field container

Field<NumPair> dict_;

The homework requires the use of char * , and not string, so that we can get better with all this low-level stuff. I've already had some question about char to wchar_t conversions, etc.

Now I have a question as to whether or not I'm destructing the NumPair properly. The scenario is as follows:

1) Field destructor gets called

template <class T>
Field<T>::~Field()
{
 delete[] v_;
}

2) Delete calls the destructor of every element NumPair in v_;

~NumPair()
{
 free(pFirst);
 free(pSecond);
}

Is this okay? I haven't really read too many articles about mixing and matching elements created on the heap and free-store as we wish. I figure as long as I don't use delete on an improper malloc'ed element, I should be fine.

However, I don't know the entire intricacies of the delete command, so I'm wondering whether or not this is valid design, and what I could do to make it better.

Also, of course this isn't. I'm getting an error of the type:

This may be due to a corruption of the heap and points to 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
}

Again, how could I improve this without the use of string?

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;
}

FIELD MEMBERS

T *v_;
size_t vsize_;
size_t vused_;

Your string handling in NumPair looks ok (strdup + free) and your Field container delete[] looks okay but it's hard to say because you don't show what v_ is.

eq mentions in a comment that you should also beware of how you are copying NumPairs. By default, C++ will give you an implicit member-wise copy constructor. This is where a RAII type like std::string makes your life easier: Your std::string containing struct can be copied without any special handling on your part and memory referenced in the string will be taken care of by the string's copy. If you duplicate your NumPair (by assigning it or returning it from a function for example) then the destruction of the temporary will free your strings out from under you.

Your copy constructor for Field just copies the pointers in v_. If you have two copies of a Field, all of the NumPairs in v_ will be deleted when the first Field goes out of scope, and then deleted again when the second one does.

Your copy constructor (of Field<>) seems OK, but the operator= is problematic.

Not only does it leak memory (what happens to the original v_ ?), but after that, two instances of Field<> hold a pointer to the same block of memory, and the one that is destructed first will invalidate the others v_ - and you can't even tell whether that has happened.

It's not always easy to decide how to deal with operator= - some think that implicit move semantics are okay, but the rest of us see how that played out with the majority of people, with std::auto_ptr . Probably the easiest solution is to disable copying altogether, and use explicit functions for moving ownership.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM