undefined reference to Foo

Discussion to talk about software related topics only.
Post Reply
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

undefined reference to Foo

Post by ckoehler »

Hi,

I am getting this linker error and don't know why. The error is related to a few methods on a custom data structure I wrote, a RingBuffer. Here's the relevant code, all files are part of the Eclipse project:
https://gist.github.com/415b35d3bca008e68f39

The error is this:

undefined reference at 'RingBuffer<float>::~RingBuffer()'

This happens twice, pointing to the delete calls of the DataController.cpp, lines 11,12 in the gist above.
Similar errors happen for the push and pop methods.

Any idea what's going on here?

Thanks!

Christoph
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: undefined reference to Foo

Post by tod »

Christoph,

When you are having an issue involving template classes it's pretty important to mention that in your post! Your problem is due to how template classes are supported. I believe that the current gcc tools (and most others) do not support the export keyword (which I didn't see you using anyway). The short version of the answer is you made a promise in the .h file that the compiler didn't keep. The linker gets upset when .h files make promises that aren't kept. You need to include your definitions of the template code in your .h file.

The long answer is to read up on this. A thorough explanation is available in Chapter 13.7 of Stroustrup's :ugeek: The C++ Programming Language.

Tod
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

Re: undefined reference to Foo

Post by ckoehler »

That would be have been nice to have learned in my data structures class. We just used one file for everything, so this never came up.

So you're saying I need to include the implementation file as well? I don't have that book, so can't look up the chapter, though I did find a site online that talks about that a bit.

Thanks for the help, really appreciate it!

Christoph
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: undefined reference to Foo

Post by tod »

If you're a student and not making any money by programming in C++ then I can see taking a pass on the book. Otherwise do yourself a favor and buy the book.
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

Re: undefined reference to Foo

Post by ckoehler »

Yep, that would be me. This is part of my grad research, so it's not something I do for a living (yet).
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

Re: undefined reference to Foo

Post by ckoehler »

Just to follow up on this, I simply stuck the content of the cpp files into the header file and call that good. I guess that's how the standard library does things, too, so I feel justified.

Thanks for the help, learned something else today!

Christoph
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: undefined reference to Foo

Post by tod »

You're probably feeling the same way I did when I realized all the definitions had to be in the .h file. It's a technique I had previously used for inlining. I haven't done detailed testing but as far as I can tell the gcc tool chain is efficient and the implementation of code may be replicated in translation object files but it isn't in the final executable.

For real-world coding I would recommend taking a look at both deque<T> and queue<T> in the STL. A ring buffer could just be a class with two data members, a queue and a maxsize. Then write your own push (so that when the max size is reached it pops off the top and pushes into the back.) You would probably also want to write a more convenient pop that combines front() and pop().

If you're open to unsolicited advice: in your code - look at your constructor and see if you didn't mean to have an initializer with : start(0). It appears to me that a user now has to new up your class and call clear() for it to operate properly. Also review your use of unsigned vs signed int. it looks to me like you should have most things as unsigned and avoid the unsigned/signed comparisons.
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

Re: undefined reference to Foo

Post by ckoehler »

Tod,

Thanks for the advice.

I looked at the queue and deque, but decided to implement my own so as not to be dependent on the STL. That's a good thing to keep in mind though.

About the start variable, you're right, and funny that you bring that up. I got access error traps because start wasn't initialized to 0 and had crazy values that made it access data in the array that wasn't there. Way off.
Incidentally, adding start = 0 in the constructor didn't fix it. I am not sure why, but it seems like the constructor was never called. Other stuff was initialized fine, just not start. I set some breakpoints in gdb to stop in the constructor, and it was stopping at the breakpoint in the push method before the constructor (which doesn't mean the constructor would be called, since it crashed here). I am kinda baffled but didn't have too much time to debug, so didn't want to post yet. All this happens in the same task, too.

I set a default constructor by setting a default value in the declaration:
RingBuffer::RingBuffer(int size=64);

But that didn't work either. Will try again tomorrow.

Thanks for the help!

Christoph
ckoehler
Posts: 81
Joined: Sat Mar 13, 2010 9:04 pm

Re: undefined reference to Foo

Post by ckoehler »

Hm, I think this may be a gcc bug:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27574

Seems like the reason it doesn't stop in a constructor is because it doesn't create debug symbols for it. Weird.
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: undefined reference to Foo

Post by tod »

That would explain why you don't see it stop there in the debugger, that doesn't mean the constructor isn't being called.
WARNING - more unsolicited advice coming - WARNING
BTW, in my response a couple of times ago I didn't say set start=0, I said to use an initializer list - there can be a big efficiency difference and you should get in the habit of using them (for all the member initialization).

You should order your member vars and objects sensibly in your declaration section (that's what determines the order they get initialized), then you should initialize everything you can (including the array) in an initializer list rather than the body of the constructor. You should initialize them in the same order they are declared. It doesn't make any practical difference it's just confusing otherwise.

You would probably benefit from using the explicit keyword for any constructor that takes a single argument. Also since you are using dynamic memory in this class it needs a copy constructor and an assignment operator. Even if you don't think you'll ever use them it's considered poor design not to declare them. If you don't want to implement them that's fine, just declare them in the private section and don't implement them. If anyone tries to use them they get a compiler error which is better than the trap they (or you) are going to get if the ones that C++ automatically creates get used.

There's a whole book of advice about these kinds of Gotcha's by Scott Meyers called Effective C++. In my not so humble opinion no one should program real world code in C++ without a thorough understanding of 90% or so of topics covered in this book.

Finally, let me say I only understand avoiding the STL if this was meant as a learning experience (which I think this was). Any real world code should make the opposite decision. If you came across this code and had to maintain it, would you rather figure out the custom approach (and hidden bugs) that some programmer developed or see a much simpler implementation that was built on top of a thoroughly tested standard library that's universally available?.
Post Reply