std :: set <myType>segfaults - PullRequest
       5

std :: set <myType>segfaults

1 голос
/ 14 февраля 2012

Я создал Тип myType вместе с набором операторов сравнения

const bool operator< (const myType& a, const myType& b);
const bool operator> (const myType& a, const myType& b);
const bool operator==(const myType& a, const myType& b);
const bool operator!=(const myType& a, const myType& b);
const bool operator<=(const myType& a, const myType& b);
const bool operator>=(const myType& a, const myType& b);

, который, как таковой, работает довольно хорошо. Также существует конструктор копирования для myType. Теперь я хочу создать набор myTypes, но получаю сбой:

#include <set>
...
namespace std;
...
myType a;                // default constructor exists
set<myType> theObjects;
theObjects.insert(a); // <-- segfaults

Понятия не имею, почему это происходит. Я был и у меня сложилось впечатление, что для использования <set> должно быть достаточно operator <. Отладчик сообщает мне, что ошибка произошла в stl_iterator.h. Кодировка в этом месте гласит:

  __normal_iterator
  operator-(const difference_type& __n) const     // <-- here is the 
                                                  // instruction pointer 
                                                  // when it crashes.
  { return __normal_iterator(_M_current - __n); }

Есть идеи у кого-нибудь? myType имеет атрибут типа vector, если это имеет значение. ОС Windows 7 Professional, компилятор g ++ из дистрибутива MinGW.

Если кто-то может что-то с этим сделать, вот трассировка стека:

 #0 77343242    ntdll!LdrLoadAlternateResourceModuleEx() (C:\Windows\system32\ntdll.dll:??)
 #1 00000000    0x7718a4ef in ??() (??:??)
 #2 77343080    ntdll!LdrLoadAlternateResourceModuleEx() (C:\Windows\system32\ntdll.dll:??)
 #3 00000002    ??() (c:/mingw/bin/../lib/gcc/mingw32/4.5.2/include/c++/bits/stl_iterator.h:775)
 #4 00000000    0x006d00c4 in ??() (??:??)

Ответ на комментарий: деструктор и оператор присваивания также существуют, но, возможно, это поможет, если я опубликую их:

конструктор:

myType::myType {
    this->init();                       // assigns NULL to a pointer attribute
    rep.push_back((unsigned short) 0);  // rep ist the vector attribute
}

конструктор копирования:

myType::myType(const myType::myType& u) : rep(u.rep) {
    this->init();                       // by intention
    this->cleanLeadingZeroes();         // removes leading zero from rep, if any
}

оператор присваивания:

myType& myType::operator=(const myType& rhs) {
    if ( this == &rhs ) return *this;
    this->rep.clear();
    this->rep = rhs.rep;
    return *this;
}

Деструктор:

myType::~myType() {
    rep.clear();
    if ( this->pointerVar != NULL ) delete this->pointerVar;
}

operator <, отвечая на другой вопрос ...

const bool operator<(const myType& a, const myType& b) {
    unsigned aNrBTs = a.size() - a.countLeadingZeroes(); // myType represents a big Int
    unsigned bNrBTs = b.size() - b.countLeadingZeroes(); // here the representations 
                                                         // are compared. size
                                                         // just returns rep.size()  
    if ( aNrBTs < bNrBTs ) return true;
    if ( aNrBTs > bNrBTs ) return false;

    for (int i = aNrBTs - 1; i >= 0; --i) {
        if ( a.get( i ) < b.get( i ) ) return true;      // get returns ith entry in 
        else if (a.get( i ) > b.get( i ) ) return false; // vector
        else continue;
    }
    return false;
}

функция инициализации:

void myType::init() {
    this->pointerVar = NULL; // pointerVar is a pointer attribute of type myType *
}

чистые ведущие нули:

void myType::cleanLeadingZeroes() {
    auto it = rep.rbegin();
    while( it!= rep.rend()) {
        if (*it != (unsigned short)0 ) break;
        ++it;
        auto end = rep.end();
        --end;
        rep.erase(end);
    }
    if (this->rep.size() == 0) rep.push_back((unsigned short)0); // make sure vector
                                                                 // contains one element
}

EDIT:

Хорошо, спасибо всем, кто уже ответил или прокомментировал это. Я мог бы немного сузить это, следуя твоему совету. Segfault происходит в конструкторе копирования, когда вектор копируется. Это происходит в stl_vector.h, кодировка выглядит следующим образом:

  size_type
  capacity() const
  { return size_type(this->_M_impl._M_end_of_storage
         - this->_M_impl._M_start); }

Здесь this->_M_impl._M_end_of_storage - 0x0, а this->_M_impl._M_start - нет. Любые идеи, почему это может иметь место, кто-нибудь?

ТИА

Thomas

1 Ответ

1 голос
/ 15 февраля 2012

Либо ваш конструктор копирования, либо ваша перегрузка оператора сравнения (<) вызывают ошибку seg, так как конструкции STL используют семантику значений, а карта использует упорядочение по <по умолчанию, если не указано явно. </p>

ТакЯ бы посоветовал закомментировать внутренние компоненты вашего конструктора копирования, а затем посмотреть, не является ли это ошибкой.Если это все еще вызывает ошибки, перейдите, чтобы попробовать то же самое в вашем операторе <- таким образом, вы будете знать, что это такое. </p>

Вы не предоставили нам определения для любой из этих трех функций:

myType::init();
myType::cleanLeadingZeroes();
const bool operator< (const myType& a, const myType& b);

Итак, мы не можем видеть, какая из этих трех функций вызывает ошибку сегмента - но это точно одна из них.Я уверен, что после того, как вы сузите ее до одной функции, это будет довольно очевидно - в противном случае вы можете добавить конкретную функцию к коду вашего вопроса, и я проверю это позже:)

РЕДАКТИРОВАТЬ

Я думаю, что вы наступаете на свой "it" итератор, вызывая erase для элемента, который вы используете в данный момент, через другой "end" итератор.

void myType::cleanLeadingZeroes() {
    auto it = rep.rbegin();               ****GET ITERATOR TO LAST ELEMENT****
    while( it!= rep.rend()) {
        if (*it != (unsigned short)0 ) break;
        ++it;                             
        auto end = rep.end();             ****GET ITERATOR TO LAST ELEMENT****
        --end;                            ****Moves from last+1 to last   ****
        rep.erase(end);                   ****ERASE LAST ELEMENT          ****
    }                                     ****LOOP CYCLE, tries to progress
                                              iterator that uses erased element****
    if (this->rep.size() == 0) rep.push_back((unsigned short)0); // make sure vector
                                                                 // contains one element
}

вызов erase () в этом случае может привести к тому, что контейнер перераспределит свое содержимое в зависимости от того, каким контейнером STL он является, что может сделать недействительными все итераторы, в данный момент указывающие на содержимое этого контейнера (в частности, в вашем случае «it» может быть признано недействительным.

Более точно:

Если вы начинаете с задней части вашего контейнера (rbegin ()) и внутри вашего цикла, вы вызываете rep.erase (end-1) (который выв основном это делается с --end, rep.erase (end), затем вы удалили элемент rbegin (). Затем вы пытаетесь перебрать этот элемент, но он больше не существует, поэтому вы не можете его использовать.

Whвам нужно создать дополнительный временный итератор для элемента, который вы хотите стереть, продвинуть свой первый итератор за ним и затем использовать временный итератор для удаления этого элемента.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...