LNK2019 Unresolved External Symbol

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
Ross91
Posts: 4
Joined: July 31st, 2018, 8:33 am

LNK2019 Unresolved External Symbol

Post by Ross91 » July 31st, 2018, 8:44 am

Hi, I've been following the awesome tutorials by chilli. So far I'm really enjoying them!

I'm currently on Tutorial 12 of the beginner C++ series, I'm now using the game constructor initialiser list to set the poo position with the random number generator.

it throws an error which is directly related to the poo constructor, although i cant figure out what is wrong. everything looks right, and I've even double checked the video. I've included the error code, and code from my project.

Error LNK2019 unresolved external symbol "public: __thiscall Poo::Poo(int,int,int,int)" (??0Poo@@QAE@HHHH@Z) referenced in function "public: __thiscall Game::Game(class MainWindow &)" (??0Game@@QAE@AAVMainWindow@@@Z) Engine C:\Users\Ross\Desktop\Chili Framework 2016-7-10\Engine\Game.obj 1

Code: Select all

Game::Game( MainWindow& wnd )
	:
	wnd( wnd ),
	gfx( wnd ),
	rng(rd()),
	xDist(0,770),
	yDist(0,570),
	Poo0(xDist(rng), yDist(rng), 1, 1 ),
	Poo1(xDist(rng), yDist(rng), -1, 1),
	Poo2(xDist(rng), yDist(rng), 1, -1)
{
}

Code: Select all

class Poo
{
public:
	Poo(int in_x, int in_y, int in_vx, int in_vy);
	void Update();
	void OverlapTest(int dudex, int dudey, int width, int height);
	void Draw( Graphics& gfx) const;
	bool IsEaten() const;
private:
	int x;
	int y;
	int vx;
	int vy;
	static constexpr int width = 24;
	static constexpr int height = 24;
	bool Eaten = false;

};

Code: Select all

class Game
{
public:
	Game( class MainWindow& wnd );
	Game( const Game& ) = delete;
	Game& operator=( const Game& ) = delete;
	void Go();
private:
	void ComposeFrame();
	void UpdateModel();
	/********************************/
	/*  User Functions              */
	void DrawEndGame(int x, int y);
	void DrawTitlePage(int x, int y);
	/********************************/
private:
	MainWindow& wnd;
	Graphics gfx;
	/********************************/
	/*  User Variables              */
	std::random_device rd;
	std::mt19937 rng;
	std::uniform_int_distribution<int> xDist;
	std::uniform_int_distribution<int> yDist;
	dude dude0;
	Poo Poo0;
	Poo Poo1;
	Poo Poo2;
	bool IsStarted = false;
	bool EndGame = false;[/quote]

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: LNK2019 Unresolved External Symbol

Post by albinopapa » July 31st, 2018, 9:21 am

Unresolved External Symbol means you haven't defined the thing you have declared.


In other words, this: Poo(int in_x, int in_y, int in_vx, int in_vy); isn't defined anywhere the compiler can see it or not defined at all. You must define the constructor, preferably in the Poo.cpp file as

Code: Select all

Poo::Poo( int in_x, int in_y, int in_vx, int in_vy)
    :
x( in_x ), y( in_y ),
vx( in_vx ), vy( in_vy )
{
}
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Ross91
Posts: 4
Joined: July 31st, 2018, 8:33 am

Re: LNK2019 Unresolved External Symbol

Post by Ross91 » July 31st, 2018, 10:41 am

Thanks for the reply, i did have my definition in my .cpp file. although I've just realised i have 'inline' included for some reason. I'm not sure how i managed to do that.

what exactly does it mean?

everything works fine now I've deleted it.

Code: Select all

inline Poo::Poo(int in_x, int in_y, int in_vx, int in_vy)
{
	x = in_x;
	y = in_y;
	vx = in_vx;
	vy = in_vy;
}

User avatar
MyK_00L
Posts: 19
Joined: June 21st, 2016, 10:44 am

Re: LNK2019 Unresolved External Symbol

Post by MyK_00L » July 31st, 2018, 1:25 pm

The "inline" keyword forces the compiler to inline the function.
That means the body of the function will be essentially copied where you call it.
This way during runtime there will be no actual function call, which can speed up the execution.
Usually the compiler understands when to inline a function anyways, so there's no real need to write inline everytime.

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: LNK2019 Unresolved External Symbol

Post by albinopapa » July 31st, 2018, 7:54 pm

There are times you are required to write inline in front of a function declaration or definition.

Header.h file

Code: Select all

#include "Vec2.h"
inline float DotProduct( const Vec2& a, const Vec2& b );
inline float CrossProduct( const Vec2& a, const Vec2& b );
inline Vec2 operator+( const Vec2& a, const Vec2& b)
{
    return { a.x + b.x, a.y + b.y };
}

float DotProduct( const Vec2& a, const Vec2& b )
{
    return ( a.x * b.x ) + ( a.y * b.y );
}

float CrossProduct( const Vec2& a, const Vec2& b )
{
    return ( a.y * b.x ) - ( a.x * b.y );
}
In this case, everything is declared and define in the header file so you must put inline in front of the declaration or else you get an error about 'multiply defined symbols'. If you have templated functions which have to be defined in the header, you don't need the inline keyword however.

As far as the compiler inlining functions for you, that can be true. Even using the keyword inline or _declspec(forceinline) still isn't a guarantee the compiler will inline your code. This is why it's futile to use inline from an optimization standpoint. As MyK_OOL points out, the compiler will inline functions it thinks will do the most good. It will depend on your project settings as well. Inlining functions causes the program to be bigger, because of the copy/paste of the contents of the function to where ever that function is called.

In a loop for instance, if you call a small function ( 2-5 lines maybe ) the contents of that function would be a good candidate for inlining, because maybe by inlining the code the compiler might also be able to unroll your loop. Unrolling the loop means instead of looping from 0 - 100 one iteration at a time, you go from 0-100 four iterations at a time.

Code: Select all

Vec2 a[100], b[100];
float c[100]{};
RandomFill( a );
RandomFill( b );

// Normal loop
for( int i = 0; i < 100; ++i )
{
    c[i] = DotProduct( a[i], b[i] );
}

// Unrolled loop
for( int i = 0; i < 100; i += 4 )
{
    c[i + 0] = DotProduct( a[i + 0], b[i + 0] );
    c[i + 1] = DotProduct( a[i + 1], b[i + 1] );
    c[i + 2] = DotProduct( a[i + 2], b[i + 2] );
    c[i + 3] = DotProduct( a[i + 3], b[i + 3] );
}
I've hear that about 20+ years ago, unrolling loops was a good practice to get more performance. The compilers today do this when beneficial just like inlining function calls. So the general rule of thumb nowadays is to just program for programmer readability first, then in the most 'mission critical' parts of your code, you can start looking for ways to optimize for speed.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

Post Reply