Pointer and Array problem - c++

In C++, I'm having trouble with pointers etc. How can I fix the following problem?
error: no match for 'operator=' in '(stage->Stage::tiles + ((unsigned int)(((unsigned int)t) * 12u))) = (operator new(12u), (, ((Tile*))))'|
note: candidates are: Tile& Tile::operator=(const Tile&)|*
stage.h
#include "Tile.h"
class Stage {
public:
Tile *tiles;
int size;
void init(int size);
};
stage.cpp
void Stage::init(int size) {
this->size = size;
this->tiles = new Tile[size];
}
application.cpp
#include "Stage.h"
#include "Tile.h"
bool setTiles( Stage * stage ) {
for( int t = 0; t < stage->size; t++ ) {
stage->tiles[t] = new Tile();
}
return true;
}
stage.init(1234);
setTiles( &stage );
Also, I don't really know when to use object.attribute and when to use object->attribute?

stage->tiles[t] = new Tile();
You're calling new on something that's not a pointer. True, tiles is a pointer to an array, however, each element of that array is NOT a pointer. In order for that work, you would need an array of pointers, or a pointer to a pointer ,such as:
Tile **tiles;
What you could also do is create a separate pointer object, allocate it, and then copy the data to your array element by using
stage->tiles[i] = *somePointer;
and then deleting the pointer afterwards to free that allocated memory. This will preserve the copy because you invoked the copy constructor.

You are trying to allocate a pointer with a pointer to an array. Try this one:
class Stage {
public:
Tile **tiles;
void init(int size);
};

stage->tiles[t] = new Tile();
The above is not a valid C++ code, which you are perhaps confusing with the way new is used in other language such as C#. Though new can be used to allocate dynamic memories, but assigning an object to a particular element in the dynamically created array doesn't need the new construct. In fact, the object is already created as soon as you called new Tile[size]. What you may want to do is, create an object of type Tile and assign it to a particular element in tiles.
Tile myTile;
// do something with myTile
this->tiles[0] = myTile;

new Tiles() returns a pointer to a Tiles instance.
Tile *tiles defines an array out Tiles, not pointers.
Start with Tile **tiles instead.

Related

How to initialize an array pointer object

I have a little problem to initialize (constructor) an array pointer of object. See the class below. Class test has 2 variable member, a pointer (value) that will be an array, and his size (size); and a constructor with parameters, and a destructor. In main function, I will create an array pointer of objects, and I have problem with it. If I create a single object like:
test obj(4); it will create a object, and his instance, value array is big 4.
Then if i want to create an array of objects:
test *obj;
obj = new test[2]{4,7};
I will create 2 object: obj[0] that is big 4, and obj[1] that is big 7.
So if I want to create more object:
test *obj;
obj=new test[100]{/*here I must write 100 numbers*/}
and this is the problem.
Because I cant write something like this:
test *obj;
obj=new int[100]{4}
I want that each value[] (instance of test class) is big 4, and I wont write 100 times "4".
I thought the analogy of declaring array:
If I write int array[5]={0,0,0,0,0}, I must write 4 times "0", or I can write also:
int array[5]={0} and each value is set to 0. (it's also true that if write int array[5]={5}, first index will be 5 and others 0).
Should I use a default constructor? What should I do?
#include <iostream>
using namespace std;
class test
{
private:
int* value;
int size;
public:
test(int size)
{
this->size = size;
value = new int[size];
}
~test()
{
delete[]value;
}
};
You can allocate the memory on the stack and get rid of dynamic allocation and memory management.
test array[100];
std::fill(std::begin(array), std::end(array), test(100));
Note that you would need a default constructor here.
You can iterate over your pointer to initialize each element
test *obj = new test[100];
for(size_t i = 0; i != 100; ++i)
{
obj[i] = test(/*parameters*/);
/* Remember to provide a move assignment operator
which invalidates the pointer member, otherwise when the
temporary variable is destroyed the new object pointer
member will point to data no more available*/
}
// ...
delete [] obj;
However it would be better to use std::vector
std::vector<test> obj(100, test(/*parameters*/));
Using std::vector your test object is initialized 100 times passing its arguments, using a pointer the allocation (new test[100]) will default construct every element, then you are going to assign each element the new value, that's why std::vector is a better solution to your problem

Is a pointer to a stack object deleted when out of scope?

I'm having a hard time trying to understand exactly what I'm supposed to do with my pointer members in my classes. I know that any pointer created with new[] must be deleted with delete[]
But, what if my pointer points to the address of an object created on the stack? Do I have to delete it? Or will it be deleted when the class is destroyed. And if so, in what way am I supposed to delete it? The clarify the issue, here's some of my code.
Moves header file: Moves.h
#pragma once
#include "ShuffleBag.h"
class Character;
class Moves
{
private:
Character* pm_User;
ShuffleBag m_HitChances;
public:
Moves (Character& user);
~Moves ();
};
We can see that I have a pointer member to a character object.
Moves Source File: Moves.cpp
#include "Moves.h"
#include "Character.h"
Moves::Moves (Character& user)
{
m_HitChances = ShuffleBag ();
m_HitChances.Add (true, 8);
m_HitChances.Add (false, 2);
pm_User = &user;
}
Moves::~Moves ()
{
}
And here we can see that I assign this pointer to the address of the passed in reference of the character object.
Character Header File: Character.h
#pragma once
#include "Moves.h"
#include "ShuffleBag.h"
class Character
{
public:
int m_Health;
int m_Energy;
Moves* pm_Moves;
public:
Character ();
Character (int health, int energy);
~Character ();
};
Likewise, here I have a pointer to a move set for this character. This is because the moves do not have a default constructor.
Character Source File: Character.cpp
#include "Character.h"
Character::Character ()
{
m_Health = 100;
m_Energy = 50;
pm_Moves = &Moves (*this);
}
Character::Character (int health, int energy)
{
m_Health = health;
m_Energy = energy;
pm_Moves = &Moves (*this);
}
Character::~Character ()
{
}
And here I assign this pointer the address of the newly created Moves object. So my question in a TL;DR format is this:
Are my pointers pointing to stack objects and when the classes die, will the pointers themselves? Or will I have to delete them?
You only need to call delete on a pointer that is returned by new. There is no exception to this rule.
In your case though,
pm_Moves = &Moves(*this);
is assigning a pointer to an anonymous temporary Moves(*this);. It's that pointer that's immediately invalided after the statement! The program behaviour on using that pointer for anything is undefined.
So you obviously need to redesign all this. Consider looking at std::unique_ptr when you refactor.
I know that any pointer created with new[] must be deleted with
delete[]
I've seen this confusion over and over again. You don't delete pointers, you delete objects. Or better to understand, if you talk about malloc / free: you don't free pointers, you free memory. The pointer just points to the object(s) / memory you need to delete.
E.g.:
int a = 24; // just an int
int* p1 = new int; // new allocates memory for an int,
// creates an int at that location
// and then returns a pointer to this newly created int
// p1 now points to the newly created int
int* p2 = p1; // p2 now also points to the created int
p1 = a; // p1 now points to a
// what do we delete now? p1?
// no, we don't delete pointers,
// we delete objects dynamically created by new
// what pointer points to those objects?
// at this line it is p2
// so correct is:
delete p2;
There is no new dynamic element created in this class, so you cannot destroy it.

C++ - Creating pointers to elements of an array containing pointers to class objects

I'm new to C++ and programming in general and am trying to learn by creating a sort of game as I go along. I can't find any information on how to achieve what I need to do.
I have created the following code, which I believe creates new objects of class Player off the heap, and creates pointers to these objects in an array.
int playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
playerArray[i].balance = 50;
playerArray[i].score = 0;
playerArray[i].playerNum = (i+1);
int m = (i+1);
playerArray[i].playerName = playerArray[i].playerN(m);
string playerNam = playerArray[i].playerName;
playerArray[i].playerAge = playerArray[i].playerA(playerNam);
playerArray[i].teamNum = 0;
}
}
where n is the number of players (from 1-4).
The class Player I have created myself:
What I now want to do is return to the calling function, main(), and still be able to access and modify these objects. I cannot figure out how. I have attempted to create pointers to each element of the array, like so:
Player** pOne = playerArray[0];
Player** pTwo = playerArray[1];
Player** pThree = playerArray[2];
player** pFour = playerArray[3];
which I think declares pOne to be a pointer to a pointer to an object of class Player (the array element), however, this throws the error:
cannot convert 'Player' to 'Player**' in initialization
doing it like this throws the same error, but in assignment rather than initialization (obviously):
Player** pOne;
pOne = playerArray[0];
How do I do it?
And, once I have done it, how do I then pass this from main() to other functions that also need to have access to these?
Would it be better to declare the array globally?
Thanks
The easiest way is probably to just return the pointer.
Player* playerObjects(int n, int gameMode)
{
Player* playerArray = new Player[n];
...
return playerArray;
}
Alternatively if you want to keep the return value as an int, you can pass a pointer to a pointer to the function. You can then create the array in the specified pointer.
int playerObjects(int n, int gameMode, Player** playerArray)
{
*playerArray = new Player[n];
for (int i = 0; i < n; i++)
{
*playerArray[i].balance = 50;
*playerArray[i].score = 0;
...
}
}
You can call this function by doing:
Player* playerArray;
playerObjects(n, gameMode, &playerArray)
And then access the items of playerArray as usual:
playerArray[0].xyz;
Don't forget that after you've allocated memory with with new[], you need to delete it with delete[] when you're finished with it.
The function musts to return (either as the return value or as a referenced parameter) the pointer to the first element of the created array. Thus in main you can use the pointer with the subscript operator.
Or more better approach is to use standard container std::vector<Player> and return it from the function.
playerArray[0] will return object of type Player, so typecast operation you are doing is incorrect.
If you want to use this array in main() then you can return playerArray from function playerObjects().

Pointer Copy to Out of Scope c++

Today i went back and investigated an error i got in an old project. It's not exactly an error, rather, i don't know how to do what i need to do. Don't really want to go into the details of the project as it is old and buggy and inefficient and more importantly irrelevant. So i coded a new sample code:
#include <iostream>
#include <vector>
#include <time.h>
#include <random>
#include <string>
class myDoc;
class myElement
{
int myInt;
std::string myString;
myElement * nextElement;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : myInt(x), myString(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<myElement> elements;
public:
void load();
~myDoc()
{
//I believe i should delete the dynamic objects here.
}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand(time(0));
myElement * curElement;
for (int i = 0; i < 20; i++)
{
int randInt = rand() % 100;
std::string textInt = std::to_string(randInt);
curElement = new myElement(randInt,textInt);
//create a new element with a random int and its string form
if (i!=0)
{
elements[i-1].nextElement = curElement;
//assign the pointer to the new element to nextElement for the previous element
//!!!!!!!!!!!! this is the part that where i try to create a copy of the pointer
//that goes out of scope, but they get destroyed as soon as the stack goes out of scope
}
elements.push_back(*curElement);// this works completely fine
}
}
int main()
{
myDoc newDoc;
newDoc.load();
// here in newDoc, non of the elements will have a valid pointer as their nextElement
return 0;
}
Basic rundown: we have a document type that consists of a vector of element type we define. And in this example we load 20 random dynamically allocated new elements to the document.
My questions/problems:
When the void myElement::load() function ends, the pointer and/or the copies of it goes out of scope and get deleted. How do i keep a copy that stays(not quite static, is it?) at least until the object it points to is deleted?
The objects in the elements vector, are they the original dynamically allocated objects or are they just a copy?
I allocate memory with new, how/when should i delete them?
Here is a picture i painted to explain 1st problem(not very accurate for the specific example but the problem is the same), and thank you for your time.
Note: I assumed you want a vector of myElement objects where each one points to the element next to it. It is unclear if you want the objects in elements to point to copies of them, anyway it should be pretty easy to modify the code to achieve the latter
This is what happens in your code:
void myDoc::load()
{
..
curElement = new myElement(n,m); // Create a new element on the heap
...
// If this is not the first element we inserted, have the pointer for the
// previous element point to the heap element
elements[i-1].nextElement = curElement;
// Insert a COPY of the heap element (not the one you stored the pointer to)
// into the vector (those are new heap elements copied from curElement)
elements.push_back(*curElement);// this works completely fine
}
so nothing gets deleted when myDoc::load() goes out of scope, but you have memory leaks and errors since the pointers aren't pointing to the elements in the elements vector but in the first heap elements you allocated.
That also answers your second question: they're copies.
In order to free your memory automatically, have no leaks and point to the right elements you might do something like
class myElement
{
int a;
std::string b;
myElement *nextElement = nullptr;
//a pointer to the element that comes immediately after this one
public:
myElement(int x, std::string y) : a(x), b(y){};
friend myDoc;
};//an element type
class myDoc
{
std::vector<std::unique_ptr<myElement>> elements;
public:
void load();
~myDoc()
{}
};// a document class that has bunch of myElement class type objects as members
void myDoc::load()
{
srand((unsigned int)time(0));
for (int i = 0; i < 20; i++)
{
int n = rand() % 100;
std::string m = std::to_string(n);
//create a new element with a random int and its string form
elements.emplace_back(std::make_unique<myElement>(n, m));
if (i != 0)
{
//assign the pointer to the new element to nextElement for the previous element
elements[i - 1]->nextElement = elements[i].get();
}
}
}
Live Example
No need to delete anything in the destructor since the smart pointers will be automatically destroyed (and memory freed) when the myDoc element gets out of scope. I believe this might be what you wanted to do since the elements are owned by the myDoc class anyway.

do I HAVE to use the new keyword?

This isn't the code I'm working on but it's the gist of what I want to do.
object *objects; int totalObjects;
void addObject(object o)
{
objects[totalObjects] = o;
totalObjects++;
}
It's giving me an access error when I try this:
Unhandled exception at 0x00e8a214 in crow.exe: 0xC0000005: Access violation writing location 0xcccccccc
Am I going to have to use 'new' and if so do I have to create a new array to copy to every time? Can I just add or take elements from the array I'm using?
Why don't you just use std::vector?
std::vector<object> objects;
void addObject(object o)
{
objects.push_back(o);
}
..or
void addObject(const object &o)
{
objects.push_back(o);
}
to remove additional copying.
When it comes to implementing your own dynamic array without std::vector, Yes. you need to allocate new memory, and copy your array to new memory block. Here's my example code with malloc and placement new.
#include <stdlib.h> // for malloc/free
#include <new> // for placement new, std::bad_alloc
object *objects = nullptr;
size_t totalObjects = 0;
void addObject(const object &o)
{
object *old_objects = objects;
size_t old_size = totalObjects;
size_t new_size = totalObjects + 1;
object *new_objects = (object *)malloc(sizeof(object) * new_size);
if (new_objects == nullptr)
throw std::bad_alloc();
size_t i;
try
{
for (i = 0; i < old_size; ++i)
{
new (&new_objects[i]) object(old_objects[i]); // placement new
}
}
catch (...)
{
// destroy new_objects if an exception occurs during creating new_objects
for (size_t j = 0; j < i; ++j)
{
new_objects[i].~object();
}
free(new_objects);
throw;
}
objects = new_objects;
free(old_objects);
}
(I haven't tested the code yet >o<)
Note that I used malloc and placement new, not new operator. It's impossible to call copy constructor of each element of the dynamic array with array-new.
However, if your object is TriviallyCopyable, you can use realloc. It can be more efficient, because realloc can just expand memory block, without copying - if the memory is enough.
..And you can select multiple lines and just press TAB in Visual Studio (..or many other editors).
You declared an object pointer, but not yet allocated the actual memory to store object objects. Your assignment statement merely tries to copy the input object o into an unallocated array member.
This is why you should use new before the assignment. The new operator asks the system to allocate some memory in the required size, then return the address of that memory and assign it to the pointer. Then, the pointer points to that newly allocated memory and the assignment (or copying) can be made.
When you finished using the array space, you should free the allocated memory using delete.
Okay, I'm going to add an answer to my own question. Let me know if this is bad etiquette. I just wanted to post some of my own code to duel with yours.
#include <vector>
std::vector<object> objects;
okay so I want to have two arrays (vectors) for the objects and double for distances so I may end up with
std::vector<double> distances;
void swap(unsigned int a, unsigned int b)
{
objects.swap_ranges(a,b);
distances.swap_ranges(a,b)
}
I'm going by the cplusplus.com reference for this function so let me know if I have it wrong. I'm going to go through it and completely redo my code.
Is there a type like the matrix that will let me hold data of different types so I don't have to invent a new object to handle each one individually?
If what you wrote is the most efficient and fast way to do this then I'll make a new class to hold both items.
thanks :)