Reputation: 9571
I have a Logger class which is expecting a std::string in the following way:
class Logger
{
public:
void Log(const std::string message);
};
And another class is calling it as:
class MyClass
{
public:
void MyMethod()
{
Logger logger;
logger.Log("Hello World!"); // This line is causing linker error.
// std::string myString("Hello World!"); If this and the line below are
// logger.Log(myString); uncommented, I get no errors.
}
};
The error message is:
Logger.cpp: undefined reference to `Logger::Log(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)`
Obviously the linker knows about the Log method, because as I showed above, the commented out lines will allow it to link properly.
Does anyone have an idea what's going on? Let me know if more information is required.
This is using gcc 4.4.3 under Linux (using Eclipse)
EDIT:
It was my understanding that you could always pass c-style strings to a method expecting an std::string because std::string has an appropriate copy constructor to handle it.
EDITx2:
Facepalm moment. I found the error. Thanks for everyone making me take a harder look at my code. See the complete solution below.
This chunk of code should have been added here in the question:
// cpp file
// This should have been in the header, not the cpp file.
inline void Logger::Log(const std::string message)
{
/* do sutff */
}
Upvotes: 1
Views: 201
Reputation: 56048
Your problem is that you haven't defined the Log
(aka Logger::Log
) method. You've declared it, but not defined it anywhere.
Another small issue is that you really ought to declare it like this:
void Log(const ::std::string &message);
There is no particularly good reason to force callers to make a copy of the string they're passing you.
There are a few possibilities that might explain why you might think it's defined, even though it isn't.
First, you may not be linking in the appropriate .o
file corresponding to the .cpp
file were the function is defined. This means you have defined it, but the linker is unaware of your definition.
Another possibility is that you've defined a function with a similar name that isn't the same function that's being called.
Another possibility is that you've defined the function to be inline. If the function is defined inline, it's possible the compiler hasn't emitted code for it. Many compilers only emit code for an inline function if the definition is available at the time it is referenced, and the manner of reference requires that the function have actual code someplace (such as taking its address).
If you have a function where the definition is inline, that function should generally be in a header file, otherwise the inline
keyword is useless, and may even cause you problems since all the rest of your code will assume there is actual code residing at a particular address backing your function declaration, except for the one .cpp
file where it appears, which may not reference the function in such a way as to force code to be emitted.
Upvotes: 1
Reputation: 222
Actually, the declaration for your member function should be
void Log( const std::string& message );
Remember that passing arguments by value means that they'll be copied. If you're only logging a little bit, it won't make a difference, but if you're logging events that occur at a high rate, the allocation/copying of the strings will start to take its toll.
It needs to be const because a logger should not modify the messages passed in and will keep the compiler from complaining when you pass in a const char* argument.
Upvotes: 0
Reputation: 6204
Your example code compiles and links fine in VC++ 2010 and gcc 4.1.2 as long as I provide a definition of the Logger::Log() method with or without the commented out code section.
Are you sure you have defined the Logger::Log() method? Have you tried duplicating the issue in the smallest possible program? If it works in the small test case then there is something more subtle causing the issue in your original code.
Another (remote) possibility since you mentioned when you uncomment the two lines it links fine is that for some reason the linker is optimizing away the Logger::Log(const std::string) method.
Upvotes: 0
Reputation: 9571
Okay, sorry, I feel like a fool.
class Logger
{
public:
void Log(const std::string message);
}
The Log method was located in its cpp file as:
inline void Log(const std::string message) { /* stuff */ }
Because it was declared inline in the cpp file, the linker wasn't finding it. Thanks everyone for constantly pushing me to take a harder look at the signature though.
For those curious, the way to fix it would be either move the method implementation to the header file so it can stay inline, or remove the inline modifier.
Upvotes: 1
Reputation: 96261
It looks like either you forgot to create the Logger::Log
function or there's an overload for char*
you aren't showing us, or you didn't link Logger.o
in the case where it failed.
Upvotes: 1