std :: set <mytype> segfaults </mytype>

时间:2012-02-14 19:57:07

标签: c++ stl set

我创建了一个类型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

我不知道为什么会这样。我和我的印象是operator <的存在应该足以使用<set>。调试器告诉我在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,MinGW发行版的编译器g ++。

如果有人可以用它做什么,这里是堆栈跟踪:

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

init函数:

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
}

编辑:

好的,感谢所有现在回答或评论过的人。我可以根据你的建议缩小范围。复制向量时,会在复制构造函数中发生段错误。它出现在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则不是。任何想法,为什么会这样,任何人?

TIA

托马斯

1 个答案:

答案 0 :(得分:1)

您的复制构造函数或比较(&lt;)运算符重载导致seg-fault,因为STL构造使用value-semantics,并且map使用&lt;如果未明确指定,则为默认值。

所以,我建议你复制你的拷贝构造函数的内部,然后看看它是否没有错误。如果它仍然是seg-fault,继续尝试在你的&lt;运算符 - 这样你就会知道它是什么。

您尚未为我们提供以下三种功能的定义:

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

所以,我们无法看到这三个函数中的哪一个导致了seg错误 - 但它肯定是其中之一。我确定在你将它缩小到一个函数之后它会非常明显 - 否则你可以将特定的函数添加到你的问题代码中,我会在以后查看它:)

修改

我认为你通过在你正在使用的元素上通过你的另一个“结束”迭代器调用erase来踩你的“it”迭代器。

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容器,这可能使当前指向该容器内容的所有迭代器无效(具体地说,在您的情况下,“它”)可能会失效。

更重要的是:

如果你从容器的后面(rbegin())开始,并在你的循环中,你调用rep.erase(end-1)(你基本上使用--end,rep.erase(end),然后你删除了rbegin()元素。然后尝试迭代该元素,但它不再存在,所以你不能使用它。

你应该做的是为要擦除的元素创建一个额外的临时迭代器,使第一个迭代器超过它,然后使用临时迭代器删除该元素。