McLovin
McLovin

Reputation: 3417

C++ link error.. is invalid?

I keep getting this Visual C++ 2010 LNK2005 linker error saying I have multiple definitions of two functions that are contained in "Error.h". (a header I made for error display)

My project is like this:

BaseImage.h
BaseImage.cpp --> includes BaseImage.h , Error.h
PNGImage.h --> includes BaseImage.h
PNGImage.cpp --> includes PNGImage.h , Error.h
main.cpp --> includes PNGImage.h

And, of course, Error.h:

/*
Optional macros:
AE_EXIT_AT_ERROR
*/
#pragma once
#include <stdexcept>

void aeError(const char *str, int code=1)
{
    throw std::runtime_error(str);
    #ifdef AE_EXIT_AT_ERROR
    std::exit(code);
    #endif
}

void aeAssert(bool b, const char *failStr = "assertion failed")
{
    if(!b)
        aeError(failStr);
}

I have #pragma once in every header file, and I tried adding include guards to Error.h as well.

Here's the compile output:

1>PNGImage.obj : error LNK2005: "void __cdecl aeError(char const *,int)" (?aeError@@YAXPBDH@Z) already defined in BaseImage.obj
1>PNGImage.obj : error LNK2005: "void __cdecl aeAssert(bool,char const *)" (?aeAssert@@YAX_NPBD@Z) already defined in BaseImage.obj
1>C:\...\Project.exe : fatal error LNK1169: one or more multiply defined symbols found

Could this be a bug?

Upvotes: 0

Views: 85

Answers (1)

R Sahu
R Sahu

Reputation: 206577

When you define functions in a .h file, make them inline. Otherwise, the function definitions are part of the object code of all the .cpp files that #include it, with external linkage.

inline void aeError(const char *str, int code=1)
{
    throw std::runtime_error(str);
    #ifdef AE_EXIT_AT_ERROR
    std::exit(code);
    #endif
}

inline void aeAssert(bool b, const char *failStr = "assertion failed")
{
    if(!b)
        aeError(failStr);
}

The other option for you is to declare the functions in the .h file and define them in exactly one .cpp file.

The .h file:

extern void aeError(const char *str, int code=1);

extern void aeAssert(bool b, const char *failStr = "assertion failed");

The .cpp file:

// Don't use inline and don't include the default argument values.

void aeError(const char *str, int code)
{
    throw std::runtime_error(str);
    #ifdef AE_EXIT_AT_ERROR
    std::exit(code);
    #endif
}

void aeAssert(bool b, const char *failStr)
{
    if(!b)
        aeError(failStr);
}

Upvotes: 2

Related Questions