views:

78

answers:

4

My program has a class with a vector of Level objects named levels. In a member function there is this line:

levels.push_back(level::Level());

I made several changes to my program today, and that line of code started segfaulting:

0x0804d248 in void std::vector<yarl::level::Level, std::allocator<yarl::level::Level> >::emplace_back<yarl::level::Level>(yarl::level::Level&&) (this=0x0, 
__args#0=...) at /usr/include/c++/4.4/bits/vector.tcc:93
93      if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)

I thought that the Level object may have somehow become corrupt, so I declared it outside the function call so I could inspect it in gdb, like this:

level::Level foo();
levels.push_back(foo);

Turns out this doesn't compile. It g++ gives two errors I haven't seen before:

error: invalid conversion from 'level::Level (*)()' to 'int'
error: initializing argument 1 of 'level::Level::Level(int, int, int)'

Now, Level's constructor takes three integer parameters, each with default values. I thought it might have been complaining that I hadn't passed those three parameters, even though they have defaults, so I changed the first line to pass the value of the defaults:

level::Level foo(1, 100, 100);

This now compiles, and still segfaults, but does so at a different spot (although an identical test):

0x0804c699 in std::vector<yarl::level::Level, std::allocator<yarl::level::Level> >::push_back (this=0x0, __x=...) at /usr/include/c++/4.4/bits/stl_vector.h:735
735     if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)

I realize this is too little code to expect you guys to be able to solve my problem, but perhaps someone could tell me a little more about what these errors mean? Those g++ errors especially; I don't know why it wouldn't accept an empty Level constructor given that all its parameters are default, and I have no idea what the (*)() part of the error means (it makes the error a very frustrating one to google).

+1  A: 

I have no idea what the (*)() part of the error means (it makes the error a very frustrating one to google).

Code like this:

Object obj();

does not create an Object instance called obj and default initialize it. It declares a function with no parameters that returns an Object instance. Apparently your vector is not templated to hold pointers to such functions.

The rest of your issues are caused be the lack of towel operator on line 42.

Noah Roberts
+5  A: 

At least one of the errors is pretty simple. This:

level::Level foo();

is a fairly common mistake in C++ known as the most vexing parse. You're not declaring a variable with the name foo and type level::Level, you're forward declaring a function with that name and return type that takes no arguments. Remove the parentheses to declare a variable

Your other calls are failing because (as indicated in the stack trace) this is NULL, but it's not obvious to me why that is, particularly as you appear to be operating on a stack variable and not a pointer

Michael Mrozek
I always thought that "most vexing parse" referred specifically to the case `T x(T());` and not to the more general `T x();`
James McNellis
@James Oh, possibly; I thought it covered both but don't know much about it
Michael Mrozek
Oh. Right. I knew that, I swear.
Max
+2  A: 
level::Level foo();

That declares a function named foo that takes no arguments and returns a level::Level. This is known as the most vexing parse. This creates a level::Level using the default constructor:

level::Level foo;

As for your original problem, you appear to have a null this pointer:

... ::push_back (this=0x0, __x=...) ...

This could happen if levels is a reference to null. Did you create the reference by dereferencing a null pointer?

Paul Kuliniewicz
A null this pointer in g++ is usually caused by using a deleted object.
Jay
`levels` is a non-pointer member of a class, declared as `std::vector<level::Level> levels;` in the class definition. Is there a way to make the `this` pointer of a non-pointer member null?
Max
I found the problem. The class that `levels` is a part of belonged to a `tr1::shared_ptr` that I was forgetting to initialize, so `levels` would definitely be null. Thanks for pointing me in the right direction, everyone.
Max
A: 

You need to read up on on the STL collection's expectations for their templated arguments. They expect at a minimum the item type template arguments to have "value" behavior. An int has value behavior because if you have

int a; // default constructor works

Then

a = 3; // assignment works
int c(a); // copy construction works

the std::vector class will work with objects that have an overloaded assignment operator and a copy constructor. std::map and some other collections need other things like comparison operator overloads.

Here's a class with a copy constructor, a default constructor, and an assignment operator overload:

class foo
{
private:
  int m_internalVal;
public:
  foo() : m_internalVal(0) { }
  foo(const foo& other) : m_internalVal(other.m_internalVal) { }
  foo& operator =(const foo& rval) { m_internalVal = rval.m_internalVal; return *this; }
};
David Gladfelter
`Level` uses the default copy constructor and assignment operators that the compiler writes, so I'm reasonably sure it's not a problem with the way the class is written. In fact, the vector push has been working for about a month, until today.
Max
If the Level class doesn't contain any pointers, handles, or other entities with reference semantics (which can result in double-deletes if Level implements ownership semantics and has a default copy constructor/assignment operator) then it must be some other problem.
David Gladfelter