Функциональный код разрывается при использовании дважды - PullRequest
0 голосов
/ 12 октября 2010

Я все еще работаю над своим классом Field и пытался улучшить мою производительность при вставке / удалении.

Однако новая функция работает один раз, а затем катастрофически прерывается, когда я использую ее второй раз.

Это код:

template <class T>
T *Field<T>::insert(const T *pPos, const T& data)
{
    // Special case:  field is empty. insert should still succeed.
    // Special case: Pointing to one past the end. insert should still succeed
    if( empty() || pPos == last() )
    {
        this->push_back(data);
        return (this->last() - 1);
    }

    /* Explanation:  Find cell before which to insert new value. Push_back new
      new value, then keep swapping cells until reaching *pPos and swapping it
      with data. The while fails, we exit, insert successful. */
    T *p = ( std::find( this->first(), this->last(), *pPos ));
    if( p != last() )
    {
        this->push_back(data);

        T *right = (this->last() - 1);
        T *left  = (this->last() - 2);
        while( *pPos != data )
            std::iter_swap( left--, right-- ); 

    // pPos *has* to be the destination of new value, so we simply return param.
        return const_cast<T*>(pPos);
    }
    else
        throw std::range_error("Not found");
}

Телефонный код от main

// Field already has push_back()ed values 10, 20, 30.
field->insert( &(*field)[2], 25 ); // field is a ptr (no reason, just bad choice)

Создает этот вывод при печати на консоли.

Field: 10 20 30    // Original Field
25                 // Function return value
Field: 10 20 25 30 // Correct insertion.

Новый код звонка от main

// Field already has push_back()ed values 10, 20, 30
field->insert( &(*field)[2], 25 );
field->insert( &(*field)[3], 35 );

Создает этот вывод при печати на консоли.

Field: 10 20 30
25
35
-4.2201...e+37, 10, 15, 20, 30

Windows has triggered a breakpoint in Pg_1.exe. 
This may be due to a corruption in the heap (oh shit).

No symbols are loaded for any call stack frame. 
The source code cannot be displayed.

Затем консоль перестанет работать, пока я сам не закрою VSC ++ 08.

Что? Зачем? Как? Что делает мой код !?

Дополнительная информация

Поле имеет размер три перед толчком и вместимость четыре. После двух вставок поле правильно увеличивается до 8 (удваивается) и сохраняет пять элементов.

Неважно, куда я вставлю свой второй элемент с помощью insert (), он точно так же потерпит неудачу. Тот же вывод, даже тот же номер (я думаю) в первой ячейке.

Дополнительный код

push_back ()

Примечание: этот код не был изменен во время моего рефакторинга. Эта функция всегда работала, поэтому я очень сомневаюсь, что это будет причиной проблемы.

/* FieldImpl takes care of memory management. it stores the values v_, vused_,
  and vsize_. Cells in the Field are only constructed when needed through a 
  placement new that is done through a helper function. */
template <class T>
void Field<T>::push_back(const T& data)
{
    if( impl_.vsize_ == impl_.vused_ )
    {
        Field temp( (impl_.vsize_ == 0) ? 1 
                                        : (impl_.vsize_ * 2) );

        while( temp.impl_.vused_ != this->impl_.vused_ )
            temp.push_back( this->impl_.v_[temp.size()] );

        temp.push_back(data);
        impl_.Swap(temp.impl_);
    }
    else
    {
// T *last()  const { return &impl_.v_[impl_.vused_]; }
// Returns pointer to one past the last constructed block.
// variant:     T *last()  const { return impl_.v_; }
        Helpers::construct( last(), data );
        ++impl_.vused_;
    }
}

Ответы [ 2 ]

1 голос
/ 12 октября 2010
// ...
if( p != last() )
{
    this->push_back(data);

После этой строки pPos может больше не быть допустимым указателем.

Затем консоль перестанет никогда не выключаться, пока я не закрою сам VSC ++ 08.

Пробовал нажимать кнопку Стоп в отладчике?

0 голосов
/ 12 октября 2010

Из отладчика и из ybungalobill можно увидеть, что pPos становится недействительным после особого случая в части кода

if( p != last()
{
    this->push_back(data);

.Если размер массива изменяется, указатель становится недействительным.Чтобы преодолеть это, я просто сохранил const T pos = *pPos до нажатия и поэтому исключил использование указателя * pPos после нажатия.

Обновленный код:

const T pos = *pPos;
T *p = ( std::find( this->first(), this->last(), pos ) );
if( p != last() )
{
    this->push_back(data);
    p = ( std::find( this->first(), this->last(), pos ) );

    T *right = (this->last() - 1);
    T *left  = (this->last() - 2);
    while( *p != data )
        std::iter_swap( left--, right-- ); 

    return const_cast<T*>(p);
}
...