Trouble passing a reference

  • (2 Pages)
  • +
  • 1
  • 2

16 Replies - 747 Views - Last Post: 20 October 2018 - 10:30 PM Rate Topic: -----

#1 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Trouble passing a reference

Posted 17 October 2018 - 11:47 PM

Hi!

In my class Maze i have the following method:

// private declaration of mGame member:
class Game* mGame;

MazeCell* Maze::CreateCell(IntVector2 coordinates)
{
	Vector3 position = Vector3((coordinates.X * tileSize) - (mSize.X * tileSize * 0.5f) - (0.5f * tileSize), 
	(coordinates.Y * tileSize) - (mSize.Y * tileSize * 0.5f) - (0.5f * tileSize), 0.0f);
	MazeCell* newCell = new MazeCell(mGame);
	newCell->SetCoordinates(coordinates);
	newCell->Initialize(position, Vector3(1.0, 1.0, 1.0));
	mCells[coordinates.X][coordinates.Y] = newCell;
	return newCell;
}



The MazeCell constructor looks like this:
MazeCell::MazeCell(Game* game)
{
	mPlaneActor = new PlaneActor(game);
	mCoordinates = IntVector2(0, 0);
}




When i try to compile, i get the following error:
error C2664: 'MazeCell::MazeCell(const MazeCell &)': cannot convert argument 1 from 'MazeCell *' to 'Game *'
But i dont understand it.
This is the line that gives all the troubles:
 MazeCell* newCell = new MazeCell(mGame); 


Could anyone please help :smile2:/>

Regards,
René

Is This A Good Question/Topic? 0
  • +

Replies To: Trouble passing a reference

#2 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 01:01 AM

You seem to be confusing yourself,

You also are not giving the true picture of the current MazeCell situation

you say that the MazeCell constructor looks like MazeCell::MazeCell(Game* game)

but somewhere there is a second constructor which looks like MazeCell::MazeCell(const MazeCell &).

This post has been edited by snoopy11: 18 October 2018 - 01:01 AM
Reason for edit:: double post

Was This Post Helpful? 0
  • +
  • -

#3 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Re: Trouble passing a reference

Posted 18 October 2018 - 01:47 AM

Hm, i cant find any other declaration of MazeCell than that one.
It is driving me crazy
Was This Post Helpful? 0
  • +
  • -

#4 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 02:07 AM

Can you post your entire MazeCell class, please?
Was This Post Helpful? 0
  • +
  • -

#5 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Re: Trouble passing a reference

Posted 18 October 2018 - 02:31 AM

I found out, that the MazeCell and CreateCell works.
The problem is somewhere around here in class Maze:

void Maze::Generate()
{
	// start maze at a random place
	IntVector2 coordinates = RandomCoordinates();

	// create a vector of activeCells
	std::vector<MazeCell> activeCells;
	
	DoFirstGenerationStep(activeCells);

	// continue looping, while we are in boundary, and we have chosen a free cell
	while (ContainsCoordinates(coordinates) && GetCell(coordinates) == nullptr )
	{
		DoNextGenerationStep(activeCells);
	}
}


MazeCell* Maze::CreateCell(IntVector2 coordinates)
{
	Vector3 position = Vector3((coordinates.X * tileSize) - (mSize.X * tileSize * 0.5f) - (0.5f * tileSize), 
			(coordinates.Y * tileSize) - (mSize.Y * tileSize * 0.5f) - (0.5f * tileSize), 0.0f);
	MazeCell* newCell = new MazeCell(mGame);
	newCell->SetCoordinates(coordinates);
	newCell->Initialize(position, Vector3(1.0, 1.0, 1.0));
	mCells[coordinates.X][coordinates.Y] = newCell;
	return newCell;
}




Here I add and removes from "activeCells", and this might be the problem.

void Maze::DoFirstGenerationStep(std::vector<MazeCell> &activeCells)
{
	activeCells.emplace_back(CreateCell(RandomCoordinates()));
}

void Maze::DoNextGenerationStep(std::vector<MazeCell> &activeCells)
{
	
	int currentIndex = activeCells.size()-1;			// see note below
	MazeCell currentCell = activeCells[currentIndex]; // might just be activeCells.back()
	MazeDirection direction = MazeDirections().RandomDirection();
	IntVector2 	coordinates = currentCell.GetCoordinates() + MazeDirections().ToIntVector2(direction); ;

	if(ContainsCoordinates(coordinates) && GetCell(coordinates) == nullptr)
	{
		activeCells.emplace_back(CreateCell(coordinates));
	}
	else
	{
		activeCells.erase(activeCells.begin() + currentIndex);	// see note above
	}
}


Was This Post Helpful? 0
  • +
  • -

#6 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 03:31 AM

Ok have it your way..


as an aside you are storing up memory leak problems with your design...
Was This Post Helpful? 2
  • +
  • -

#7 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Re: Trouble passing a reference

Posted 18 October 2018 - 12:36 PM

I see what you mean.
I will need some cleanup too. actually i was trying to convert some Unity C# code to C++
Was This Post Helpful? 0
  • +
  • -

#8 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 02:51 PM

Well converting from one language to another can be tricky,

you have to have a pretty good handle on both languages.
Was This Post Helpful? 0
  • +
  • -

#9 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6502
  • View blog
  • Posts: 22,267
  • Joined: 05-May 12

Re: Trouble passing a reference

Posted 18 October 2018 - 07:31 PM

The basic problem here is that our OP has forgotten that most things in C# are by reference, unless you are dealing with value types, while in C++ everything is by value. So he is trying to emplace a MazeCell * returned by CreateCell() into a std::vector<MazeCell>. The vector contains MazeCell objects, and so the emplace_back() is trying to use a copy constructor. This is evidenced by the error message referring to the copy constructor MazeCell::MazeCell(const MazeCell &).

Here is a minimal reproduction of the problem:
#include <vector>

class Bar
{
};

class Foo
{
public:
    Foo(Bar * bar)
        : m_bar(bar)
    {
    }

private:
    Bar * m_bar;
};

int main()
{
    std::vector<Foo> foos;
    Bar * pbar = new Bar();
    Foo * pfoo = new Foo(pbar);

    foos.emplace_back(pfoo);

    return 0;
}



With VS2017 the error I get back is:
Severity	Code	Description	Project	File	Line	Suppression State
Error	C2664	'Foo::Foo(Foo &&)': cannot convert argument 1 from 'Foo *' to 'Bar *'	SimpleCppConsole	c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.15.26726\include\xmemory0	881	


The compiler is trying to use the move constructor instead of the copy constructor, but it is essentially the same problem.

The way to fix the problem is to pass in a real object to be emplaced instead of a pointer to an object.
Was This Post Helpful? 2
  • +
  • -

#10 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 08:37 PM

Ahh,

Very well worked out....!


But can you not just fix it by doing..?

std::vector<Foo*> foos;


or in other words...in the OP's code


std::vector<MazeCell*> activeCells;



and

void Maze::DoFirstGenerationStep(std::vector<MazeCell*> &activeCells)
{
	activeCells.emplace_back(CreateCell(RandomCoordinates()));
}

void Maze::DoNextGenerationStep(std::vector<MazeCell*> &activeCells)
{
	
	int currentIndex = activeCells.size()-1;			// see note below
	MazeCell currentCell = activeCells[currentIndex]; // might just be activeCells.back()
	MazeDirection direction = MazeDirections().RandomDirection();
	IntVector2 	coordinates = currentCell.GetCoordinates() + MazeDirections().ToIntVector2(direction); ;

	if(ContainsCoordinates(coordinates) && GetCell(coordinates) == nullptr)
	{
		activeCells.emplace_back(CreateCell(coordinates));
	}
	else
	{
		activeCells.erase(activeCells.begin() + currentIndex);	// see note above
	}
}



Asking for a friend :whistling:
Was This Post Helpful? 2
  • +
  • -

#11 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6502
  • View blog
  • Posts: 22,267
  • Joined: 05-May 12

Re: Trouble passing a reference

Posted 18 October 2018 - 08:44 PM

Yes, if the Foo is a base class that will later be used for polymorphic calls, using a pointer would the correct solution, albeit as you pointed our earlier, a nice source of memory leaks. A better choice would be to use a vector of smart pointers to Foos. Let the smart pointers take care of reference counting the object and deciding when to free up the memory.

If there are no plans for polymorphic calls, and copying a Foo is relatively cheap, then the standard thing to do in modern C++ is to prefer to keep vectors of objects, rather than vectors of pointers to objects.

Side note: there's a few places above where the dots (.) need to be replaced with arrows (->) as well as the types of the local variables.
Was This Post Helpful? 1
  • +
  • -

#12 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 18 October 2018 - 08:57 PM

Oh well, don't get me started on the memory leaks this program is generating everywhere....!!

Yes exactly what I thought then, not really sure if CreateCell really requires returning a pointer, what is the point?

So you're saying your problem would best be solved something like

#include <vector>

class Bar
{
};

class Foo
{
public:
    Foo(Bar& bar)
        : m_bar(bar)
    {
    }

private:
    Bar  m_bar;
};

int main()
{
    std::vector<Foo> foos;
    Bar pbar;
    Foo pfoo(pbar);

    foos.emplace_back(pfoo);

    return 0;
}




With the added benefit of 'no memory leaks,' I think I will leave the OP to work out the rest
Was This Post Helpful? 1
  • +
  • -

#13 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Re: Trouble passing a reference

Posted 19 October 2018 - 12:50 AM

Hi guys.
Thanks for the help.
When I get home tomorrow, i will have a serious look at my code again.
Also i need to destroy the objects when they get out of scope, correct? (iterate through vectors and delete the objects)
Was This Post Helpful? 0
  • +
  • -

#14 snoopy11   User is offline

  • Engineering ● Software
  • member icon

Reputation: 1550
  • View blog
  • Posts: 4,930
  • Joined: 20-March 10

Re: Trouble passing a reference

Posted 19 October 2018 - 01:23 AM

No,

what you 'new' you must 'delete' is the rule...

when objects go out of scope they are destroyed and vectors handle their own deletion unless its a vector of pointers.
Was This Post Helpful? 1
  • +
  • -

#15 tandpine   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 20-April 18

Re: Trouble passing a reference

Posted 20 October 2018 - 03:58 AM

Hi guys!
I followed Skydivers recomendation, and made it vectors of MazeCell instead of pointers.

// snip from Maze.h
private:
	void DoFirstGenerationStep(std::vector<MazeCell>& activeCells);
	void DoNextGenerationStep(std::vector<MazeCell>& activeCells);

	std::vector<std::vector<class MazeCell> > mCells;

// snip from Maze.cpp
void Maze::Initialize(int width, int height)
{
	Random::Init();
	mSize = IntVector2(width, height);

	// Initialize mCells vector
	mCells.resize(mSize.X);
	for (int x = 0; x<mSize.X; x++)
	{
		// create a tempVector of size mHeight
		std::vector<MazeCell> tmpVector;
		// add new MazeCells to it
		for (int y = 0; y < mSize.Y; y++)
		{
			tmpVector.push_back(MazeCell(mGame)); 
		}
		mCells[x] = tmpVector;
	}
}

void Maze::Generate()
{
	// start maze at a random place
	IntVector2 coordinates = RandomCoordinates();

	// create a vector of activeCells
	std::vector<MazeCell> activeCells;

	DoFirstGenerationStep(activeCells);
	
	// continue looping, while we are in boundary, and we have chosen a free cell
	while (ContainsCoordinates(coordinates) && GetCell(coordinates).IsActive())
	{
		DoNextGenerationStep(activeCells);
	}

	for (auto ite : activeCells)
	{
		IntVector2 coord = ite.GetCoordinates();
		SDL_Log("Coordinates: %i, %i", coord.X, coord.Y);
	}
}

void Maze::DoFirstGenerationStep(std::vector<MazeCell>& activeCells)
{
	activeCells.emplace_back(CreateCell(RandomCoordinates()));
}

void Maze::DoNextGenerationStep(std::vector<MazeCell>& activeCells)
{
	
	int currentIndex = activeCells.size()-1;			// see note below
	MazeCell currentCell = activeCells[currentIndex]; // might just be activeCells.back()
	MazeDirection direction = MazeDirections().RandomDirection();
	IntVector2 	coordinates = currentCell.GetCoordinates() + MazeDirections().ToIntVector2(direction); ;

	if(ContainsCoordinates(coordinates) && GetCell(coordinates).IsActive())
	{
		activeCells.emplace_back(CreateCell(coordinates));
	}
	else
	{
		activeCells.erase(activeCells.begin() + currentIndex);	// see note above
	}
}



It took away the compilation errors, and the two "&" created references to the correct "activeCells"
Now I just have to do some debugging, to find some faults :detective:

THANK YOU!
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2