1

I created a Type myType together with a set of comparison operators

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

which, as such, works quite well. A copy constructor exists, too, for myType. Now I want to create a set of myTypes, but get a crash:

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

I have no idea why that happens. I was and I am under the impression, that the existence of operator < should be sufficient to use <set>. The debugger tells me the segfault happens in stl_iterator.h. The coding at that place reads:

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

Any ideas anyone? myType has an attribute of type vector, in case that matters. OS is Windows 7 Professional, compiler g++ from the MinGW distribution.

In case anyone can do something with it, here's the stack trace:

 #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 ??() (??:??)

Answering on a comment: destructor and assignment operator exist, as well, but maybe it helps if I post them:

the constructor:

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

the copy constructor:

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

the assignment operator:

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

the destructor:

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

operator <, responding to another question...

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

the init function:

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

the clean leading zeroes:

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:

Ok thanks to all who answered or commented on this by now. I could narrow this down a bit following your advice. The segfault occurs in the copy constructor, when the vector is copied. It occurs in stl_vector.h, the coding looks as follows:

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

Here, this->_M_impl._M_end_of_storage is 0x0, while this->_M_impl._M_start is not. Any ideas why this may be the case, anyone?

TIA

Thomas

Thomas
  • 1,160
  • 3
  • 16
  • 34
  • 4
    How about showing us the definition of `myType`? Since you mentioned a copy constructor but not a destructor or copy-assignment operator, I suspect that you're violating the [Rule of Three](http://stackoverflow.com/q/4172722/636019) and observing memory corruption. – ildjarn Feb 14 '12 at 20:00
  • Hi, thanks for pointing that out. I added the details to the question. – Thomas Feb 14 '12 at 20:16
  • What's the definition for `myType::operator<`? – Georg Fritzsche Feb 14 '12 at 20:29
  • In response to your edit, a vector copy of a trivial type (one you didn't make yourself) will almost certainly not fail except possibly if it runs out of memory in your system which isn't likely unless this is a huge dataset. If your vector is of a user-defined type, then you probably messed up that type's copy constructor as well, otherwise you may be chasing a red herring and the problem could be somewhere else. I still think your cleanLeadaingZeroes() function will seg-fault on the first iteration personally. I'm out for the night though - good luck with your problem! – John Humphreys Feb 14 '12 at 21:16
  • @w00te Many thanks for your efforts. Next thing I'll try is to compile and run this on a linux box. – Thomas Feb 14 '12 at 21:21

1 Answers1

1

Either your copy constructor or your comparison (<) operator overload are causing the seg-fault as STL constructs use value-semantics, and a map uses ordering by < as default if not specified explicitly.

So, I'd suggest commenting out the internals of your copy constructor, then see if it doesn't seg fault. If it still seg-faults, move on to try the same in your < operator - that way you'll know which it is.

You haven't provided us definitions for any of these three functions:

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

so, we can't see which one of those 3 functions is causing the seg fault - but it's one of them for sure. I'm sure after you narrow it down to a single function it will be fairly obvious - otherwise you can add the specific function to your question's code and I'll check it out later :)

EDIT

I think you're stepping on your "it" iterator by calling erase on the element you're currently using through your other "end" iterator.

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
}

The call to erase() in this case may may cause the container to reallocate its contents depending on which STL container it is, which could invalidate all iterators currently pointing to that container's contents (specifically, in your case, "it" may be invalidated.

More to the point:

If you start at the back of your container (rbegin()), and within your loop, you call rep.erase(end-1) (which you basically do with --end, rep.erase(end), then you've deleted the rbegin() element. You then try to iterate off of that element, but it doesn't exist anymore so you cant use it.

What you should do is create an extra temporary iterator to the element you want to erase, progress your first iterator past it, and then use the temporary iterator to delete that element.

John Humphreys
  • 37,047
  • 37
  • 155
  • 255
  • I provided the definitions of the 3 functions. Thanks for replying. – Thomas Feb 14 '12 at 20:48
  • Thanks for the suggestion. I changed the method. I now check whether rep[rep.size() - 1] != 0 (then I exit) otherwise I delete the last element of the vector. It still segfaults. The debugger does not stop in that method, either, and that method has been tested several thousand times without segfaulting, so I doubt it's the culprit. – Thomas Feb 14 '12 at 21:17