I have a table object with the following header file:
#ifndef TABLE_H
#define TABLE_H
#include "Order.h"
#include "Waiter.h"
// 0 1 2 3
enum TableStatus { IDLE, SEATED, ORDERED, SERVED };
class Waiter; // to take care of circular reference.
class Table
{
private:
int tableId; // table number
const int maxSeats; // table seat capacity
TableStatus status; // current status, you can use assign like
// status = IDLE;
int numPeople; // number of people in current party
Order *order; // current party's order
Waiter *waiter; // pointer to waiter for this table
public:
Table(int tblid =0, int mseats = 0); // initialization, IDLE
void assignWaiter(Waiter *person); // initially no waiter
void partySeated(int npeople); // process IDLE --> SEATED
void partyOrdered(Order *order); // process SEATED --> ORDERED
void partyServed(void); // process ORDERED --> SERVED
void partyCheckout(void); // process SERVED --> IDLE
int getMaxSeats(void);
int getStatus(void);
};
#endif
in my main function, I need to declare an array of tables. But when I write, say, Table *table = new Table[10], every element of the array calls the default arguments in the constructor, and every table ends up with a constant maximum seat value of 0. I need to be able to individually call each of their constructors to have different values for the maxSeats.
The only solution I've been able to come up with so far is to declare an array of pointers to table objects, and then instantiate each one separately. This partially works, but the Waiter class mentioned in the code above accepts an array of Tables as an argument, and won't work if it's passed an array of Table pointers.
What process can i perform to end up with an array of Table objects with differing values for their maxSeats constant variable?
One more point of clarification: The array has to be dynamically created, so I can't just explicitly make 10 or however many calls to the constructor. I don't know in advance how large the array must be.
One option is to use placement new:
Table* tables = static_cast<Table*>(new char[sizeof(Table) * count]);
for(int i = 0; i < count; i++) new(&tables[i]) Table(tblid[i], mseats[i]);
You can use a placement new in this particular situation, but do not forget to manually destruct your objects, and deallocate the raw memory with operator delete[] : (If you don't, your program will have undefined behavior)
Here is a minimal example of a placement new with array objects:
#include <new>
class MyClass
{
public:
MyClass(int i) : p(i) {}
private:
int p;
};
int main(int argc, char** argv) {
// Allocate a raw chuck of memory
void* buff10 = operator new[](sizeof(MyClass) * 10);
MyClass * arr = static_cast<MyClass*>(buff10);
// Construct objects with placment new
for(std::size_t i = 0 ; i < 10 ; ++i)
new (arr + i) MyClass(i);
// Use it ...
// Then delete :
for(std::size_t i = 9 ; i >= 0 ; --i)
arr[i].~MyClass();
operator delete[] (arr);
return 0;
}
It's not possible to do this with new. But you should not be using new anyway. Use vector instead. Before C++11 it can't really cope with a const member, but in C++11 you have some options:
std::vector<Table> table = {
{ 1, 1 }, {2, 2}, {3, 3}, /* etc. */ };
Or you can add one by one:
std::vector<Table> table;
table.emplace_back( Table(1, 1) );
table.emplace_back( Table(2, 2) );
Since your class contains a const that makes it non-copyable. However it is still MoveConstructible.
Note: It probably makes things a lot easier here if you don't have a const class member, just keep it private and don't change it.
Also, depending on what you do with order and waiter, the default move constructor might not do the right thing. If these point to resources which are "owned" by the table then you will have to either manage these resources properly, or write your own a move constructor.
Related
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
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.
I want to create an unknown number of objects each with a specific object name inside the main-method at runtime. The objects should be existent until the program ends (main-method ends). Note, that in my case the objects are Fields.
I thought about a solution like this:
for ( i=1 ; i <= NumberOfObjects ; i++)
{
if (i==1)
{
MyClass *ObjectName1 = new MyClass();
}
if (i==2)
{
MyClass *ObjectName2 = new MyClass();
}
. //more if statements for more objects
.
.
} //for loop closed
Questions:
I don't think this solution is good, since the number of created objects still would be limited to the if-statements within the for-loop. Any better solutions?
Scope of pointers in loops: When the if-blocks are exited the pointers are out of scope. How can I access the with "new" created objects afterwards?
Named variables are removed once the code is compiled and doesn't mean anything to you afterwards.
Looks like you need a look up table, use an std::map or std::unordered_map with string key as the name of the object.
std::map<std::string, MyClass*> variablesTable;
for ( i=1 ; i <= NumberOfObjects ; i++)
{
std::ostringstream oss << "name" << i;
variablesTable[oss.str()] = new MyClass(); //you actually need to check if it exists, otherwise will be overwritten.
}
As if you want each created to run a separate code for each object, you can have a table of function objects (or just store both in a tuple) like this std::map<std::string, std::<MyClass, Func>>.
If you want to lookup just use,
MyClass* object = variablesTable[strName];
object->CallFunction();
P.S. A known trick for hash_maps is to run script before building the project to convert any literal string to int, because comparing int is faster than strings. At least I know this was used in the Uncharted series (but hardly relevant to your case).
To elaborate on your approach, there is no need for a loop. You can simplify this to
MyClass *ObjectName1 = new MyClass();
MyClass *ObjectName2 = new MyClass();
MyClass *ObjectName3 = new MyClass();
...
The scope and the lifetime of the pointer already ends, when you leave the if statement. To access the pointers outside the if/for statements, you have to move them before the loop.
I would just use a std::vector of objects
std::vector<MyClass*> objects;
for (int i = 1; i <= NumberOfObjects; i++) {
MyClass *p = new MyClass();
objects.push_back(p);
}
This won't give you an individual name for each object, but is maintainable at least.
Update:
To address the concerns of leaking memory, you can also create the objects directly in the vector without an explicit new
std::vector<MyClass> objects;
for (int i = 1; i <= NumberOfObjects; i++)
objects.push_back(MyClass());
This will give you the objects and they will be cleaned automatically, when the scope of the vector ends.
You will need something to store that objects. For example you could use a std::vector, or a std::map. You can store an unlimited number of objects (actually you're limited by your memory amount, let's say almost unlimited) inside these data structures, without caring about the memory since it's managed automatically.
EDIT: OK, that's not an answer. OP wants arbitrary object count at run time!
That question may be a template meta programming one.
Use a vector to store the pointer, use a macro to define a new pointer and push it to the vector.
Before ending, use the vector to free.
#include <vector>
#define DEFVAR( varname ) \
foo* varname = new foo(); \
v.push_back( varname )
class foo {};
int main() {
std::vector<foo*> v;
DEFVAR( ObjName1 );
DEFVAR( ObjName2 );
DEFVAR( ObjName3 );
DEFVAR( ObjName4 );
[ .... ]
for ( size_t index = 0; index < v.size(); ++index ) delete v[ index ];
return 0;
}
I have a class called Foo which has a member that is a pointer to a vector of pointers to another class called Bar. I initialise it in the constructor but I'm not sure how to deallocate it in the destructor. I'm still learning. Would appreciate your help. The reason for having this member is so that the scope persists beyond that method i.e. beyond the stack. Thanks.
#include <iostream>
#include <vector>
using namespace std;
class Bar {};
class Foo {
public:
Foo() {
bars = new vector<Bar*>*[10];
for (int i = 0; i < 10; i++) {
bars[i]->push_back(new Bar());
}
}
~Foo () {
for (int i = 0; i < 10; i++) {
// TODO: how to clean up bars properly?
}
}
private:
vector<Bar*>** bars;
};
int main () {
new Foo();
return 0;
}
Update: I appreciate the feedback on all fronts. I'm new to C and C++. Basically I wanted a 2d structure as a class member that would persist for the lifetime of the class. The reason the outer structure is an array is because I know how big it needs to be. Otherwise I was previously using vector of vectors.
This isn't even allocated properly. You allocate an array of pointers to std::vector<Bar*>, but never any std::Vector<Bar*>.
The best thing to do is just something like std::vector<std::unique_ptr<Bar>> or even std::unique_ptr<std::vector<std::unique_ptr<Bar>>> or something like that. What you've got is just WTF.
Or std::unique_ptr<std::array<std::unique_ptr<std::vector<std::unique_ptr<Bar>>>, 10>>.This is an exact match (but self-cleaning).
The number of pointers is a bit ridiculous, as all they are doing is causing confusion and leaks, as evident from non-proper initialization and the question's title. You don't actually need any pointers at all, and don't have to worry about any cleanup.
For a 2D array with the first dimension passed into the constructor, you can use a vector of vectors:
std::vector<std::vector<Bar>> bars;
To initialize the outer vector with the passed in size, use an initializer:
Foo(size_t size)
: bars(size) {}
When the object is destroyed, bars and all of it elements are as well, so there's no chance of forgetting to clean up or doing so improperly.
If performance is an issue, this can be translated into a sort of Matrix2D class that acts like a 2D array, but really only has an underlying 1D array.
EDIT: In the case of a 2D structure (and you said you know how big your 2D structure needs to be, so we'll assume that the 10 in your loops is the size of the 2D array you desire.
#include <iostream>
#include <vector>
using namespace std;
class Bar {
public:
int BarInfo;
};
class Foo {
public:
Foo() {
// Allocates 10 vector spots for 10 bar elements - 100 bars, 10 x 10
for (int i = 0; i < 10; i++) {
// Puts 10 bars pointer at the end;
// Heap-allocated (dynamically), which
// means it survives until you delete it
// The [10] is array syntax, meaning you'll have 10 bars
// for each bars[index] and then
// you can access it by bars[index][0-9]
// If you need it to be more dynamic
// then you should try vector<vector<Bar>>
bars.push_back(new Bar[10]);
}
}
Bar* operator[] (int index) {
return bars[index];
}
~Foo () {
// Cleanup, because you have pointers inside the vector,
// Must be done one at a time for each element
for (int i = 0; i < bars.size(); i++) {
// TODO: how to clean up bars properly?
// Each spot in the vector<> contains 10 bars,
// so you use the array deletion
// and not just regular 'delete'
delete[] bars[i]; // deletes the 10 array elements
}
}
private:
// vector might not be a bad idea.
vector<Bar*> bars;
};
This is the main I have for testing the code written, and it works like you would think a 2D array should work:
int main ( int argc, char* argv[] ) {
Foo foo;
// Bar at 1st row, 2nd column ( row index 0, column index 1 )
// Bar& is a reference
Bar& bar12 = foo[0][1];
bar12.BarInfo = 25;
int stuffInsideBar = foo[0][1].BarInfo; // 25
return 0;
}
I hope that helps and gets you closer to what you're doing. I've used a technique here that might go over a starters head to make the Foo class behave like you would think a 2D array would. It's called operator overloading. It's a powerful feature in C++, so once you master more basics it might be useful to you in your future projects or current one. Good luck!
~~~~~~~~~~~~~~~~~~~~~~~
OLD ANSWER BEFORE EDIT
~~~~~~~~~~~~~~~~~~~~~~~
It appears you're doing far too much indirection. While another person's answer shows you how to clean up what you've managed to do, I think you could benefit from changing how exactly you're handling the class.
#include <iostream>
#include <vector>
using namespace std;
class Bar {};
class Foo {
public:
Foo() : bars() {
// bars is no longer a pointer-to-vectors, so you can just
// allocate it in the constructor - see bars() after Foo()
//bars = new vector<Bar>();
for (int i = 0; i < 10; i++) {
// Puts 1 bar pointer at the end;
// Heap-allocated (dynamically), which
// means it survives until you delete it
bars.push_back(new Bar());
}
}
~Foo () {
// Cleanup, because you have pointers inside the vector,
// Must be done one at a time for each element
for (int i = 0; i < 10; i++) {
// TODO: how to clean up bars properly?
// TODOING: One at a time
delete bars[i]; // deletes pointer at i
}
}
private:
// You don't need to ** the vector<>,
// because it's inside the class and
// will survive for as long as the class does
// This vector will also be copied to copies of Foo,
// but the pointers will remain the same at the time
// of copying.
// Keep in mind, if you want to share the vector, than
// making it a std::shared_ptr of a
// vector might not be a bad idea.
vector<Bar*> bars;
};
If you pass the class by reference into functions, than the vector<Bar*> inside the class won't copy itself or delete itself, making it persist past a single stack frame.
In your main, this should clean up properly and is a lot easier to keep track of than vector** . However, if for some reason vector** is required, than home_monkey's answer should help you more.
I think there is an issue with allocation. The line
new vector <Bar*> * [10]
will give you an array of points to objects of type vector <Bar*> * and you
will need to allocate some additional memory for your vector <Bar*> type.
I've had a go,
Foo()
{
bars = new vector<Bar*>*[10]; // A.
for (int i = 0; i < 10; i++)
{
bars[i] = new vector<Bar*>; // B. Extra memory assigned here.
bars[i]->push_back(new Bar); // C.
}
}
To free resources, you'll have to reverse the above
~Foo ()
{
for (int i = 0; i < 10; i++)
{
// I'm assuming that each vector has one element
delete bars[i][0]; // Free C
delete bars[i]; // Free B
}
delete [] bars; // Free A
}
I don't believe you're even allocating it properly. To undo what you've done so far, all you'd have to do is:
for(int i=0; i < 10; ++i)
while(bars[i]->size > 0)
{
delete *bars[i]->front();
pop_front();
}
delete[] bars;
But, you need to allocate each of the vectors themselves, for instance in the constructor:
for(int i=0; i<10; ++i)
bars[i] = new vector<Bar*>();
Which would require you change the destructor to:
for(int i=0; i < 10; ++i)
{
while(bars[i]->size > 0)
{
delete *bars[i]->front();
pop_front();
}
delete bars[i];
}
delete[] bars;
With regard to your update, I would then suggest changing the type of bars to:
vector<Bar*>* bars;
and the allocation to (without the need to do the for loop allocation suggested above):
bars = new vector<Bar*>[10];
Is it safe to return a vector that's been filled with local variables?
For example, if I have...
#include <vector>
struct Target
{
public:
int Var1;
// ... snip ...
int Var20;
};
class Test
{
public:
std::vector<Target> *Run(void)
{
std::vector<Target> *targets = new std::vector<Target>;
for(int i=0; i<5; i++) {
Target t = Target();
t.Var1 = i;
// ... snip ...
t.Var20 = i*2; // Or some other number.
targets->push_back(t);
}
return targets;
}
};
int main()
{
Test t = Test();
std::vector<Target> *container = t.Run();
// Do stuff with `container`
}
In this example, I'm creating multiple Target instances in a for loop, pushing them to the vector, and returning a pointer to it. Because the Target instances were allocated locally, to the stack, does that mean that the returned vector is unsafe because it's referring to objects on the stack (that may soon be overwritten, etc)? If so, what's the recommended way to return a vector?
I'm writing this in C++, by the way.
Elements get copied when you push_back them into a vector (or assign to elements). Your code is therefore safe – the elements in the vector are no references to local variables, they are owned by the vector.
Furthermore, you don’t even need to return a pointer (and never handle raw pointers, use smart pointers instead). Just return a copy instead; the compiler is smart enough to optimise this so that no actual redundant copy is made.