String and function object - c++

I encountered this issue, but I'm not sure what to make of it...
class Goo
{
char _ch;
string _str;
public:
function<void(void)> dobedo;
// Constructor 1
Goo(string s) : _str(s)
{
cout << "Constructed: [" << &_str << "]: " << _str << endl;
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}
// Constructor 2
Goo(char ch) : _ch(ch)
{
dobedo = [&]() {
cout << "Dobedo: " << _ch << endl;
};
}
void show() { cout << "Show: [" << &_str << "]: " << _str << endl; }
};
int main()
{
string myStr1("ABCD");
string myStr2("EFGH");
vector<Goo> goos;
goos.push_back(Goo(myStr1));
goos.push_back(Goo(myStr2));
goos[0].dobedo();
goos[1].dobedo();
goos[0].show();
goos[1].show();
return 0;
}
For some reason, the function object wasn't able to print _str, despite being able to locate the memory address:
Constructed: [00EFF80C]: ABCD
Constructed: [00EFF7B0]: EFGH
Dobedo: [00EFF80C]:
Dobedo: [00EFF7B0]:
Show: [032F2924]: ABCD
Show: [032F296C]: EFGH
I did not have any problems with char variables though.
int main()
{
vector<Goo> goos;
goos.push_back(Goo('#'));
goos.push_back(Goo('%'));
goos[0].dobedo();
goos[1].dobedo();
return 0;
}
The output gives:
Dobedo: #
Dobedo: %
Any ideas?

You have undefined behaviour in your code without defining copy constructor. Default copy constructor copies all members by value. So your lambda object is copied and it holds references to destroyed object - _str (when vector had to be reallocated while calling push_back method).
Define copy constructor and move constructor for Goo class:
Goo(const Goo& g)
{
_str = g._str;
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}
Goo(Goo&& g)
{
_str = move(g._str);
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}

Your output clearly shows that the address of _str in constructor isn't the same as one in show. It means that your object was copied/moved. It may happen while it is pushed to a vector. BTW, it also may take place when you push/pop other elements to/from a vector as vector doesn't guarantee elements to stay at the same memory address.
When you create dobedo functor, all captured fields are copied to it. In the first case it was the address of _str which becomes invalid when the object is copied/moved (nobody updates it upon a move/copy!). Occasionally we may find an empty-string like stuff at that address (although accessing it is now a memory violation). In the second case, a character is captured and stored - and it definitely remains valid upon any object location change.

Related

range-v3: Concatenate a range and a single value without copying or moving?

How can a vector of objects and a single object be iterated over as-if they were the same range, without any copying or moving, in range-v3?
One possibility is to cast the single value to a std::array<Object, 1> and then concatenate this array with the vector of objects via range::views::concat:
Improvised solution
#include <array>
#include <iostream>
#include <range/v3/view/concat.hpp>
struct Object {
int value = 0;
Object() { std::cout << "Default " << value << "\n"; }
Object( int value) : value(value) { std::cout << "Value " << value << "\n"; }
Object(Object const& object) : value(object.value) { std::cout << "Copy " << value << "\n"; }
Object(Object && object) : value(std::move(object.value)) { std::cout << "Move " << value << "\n"; }
};
int main() {
// Prints "Value 0"
std::array<Object, 1> objects {0};
// Prints "Value 1"
Object object {1};
for(Object const& object : ranges::views::concat(objects, *reinterpret_cast<std::array<Object, 1>*>(&object))) {
// Prints "0 1"
std::cout << object.value << " ";
}
return 0;
}
I don't know if the cast is safe. Assuming it is, developers are at risk of having to spend time to verify this. Hence this improvised solution is wanting.
Question: Is there an elegant solution for concatenating a view and a single value without copying or moving data?
I am aware of range::views::single but this causes object to be copied once and moved thrice when used in place of reinterpret_cast in the improvised solution.

double free while using vector and strings

I wrote the following function and a simple class, while trying to understand how expensive a work with vector can be.
void gen_random(string & str, const int len)
{
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
srand((unsigned int)time(NULL));
str.reserve(len);
for (int i = 0; i < len; ++i)
{
str += alphanum[rand() % (sizeof(alphanum) - 1)];
}
}
class Person
{
public:
//CTOR with parameter
Person(u_int32_t Id)
{
std::cout << "\033[1;32mPerson CTOR: " << Id << "\033[0m" << std::endl;
m_Id = Id;
m_RandSid = new string;
gen_random(*m_RandSid, 10);
}
//CCTOR
Person(const Person & p)
{
std::cout << "\033[1;31mPerson CCTOR: " << p.m_Id << "\033[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid; //trigger string operator=()
}
//MCTOR
Person(Person&& p)
{
std::cout << "\033[1;34mPerson MCTOR: " << p.m_Id << "\033[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid;
p.m_RandSid = nullptr;
}
//DTOR
~Person()
{
std::cout << "\033[1;33mPerson DTOR: "<<m_Id <<"\033[0m"<< std::endl;
if (nullptr != m_RandSid)
{
delete m_RandSid;
}
}
u_int32_t m_Id;
string * m_RandSid;
};
and driver :
int main()
{
int a;
vector<Person> v;
for (int i = 0; i < 2; ++i)
{
std::cout <<std::endl<< "inserting person #" << i << std::endl;
std::cout << "Vector size = " << v.size()<< " Vector capacity = " << v.capacity() << std ::endl;
v.emplace_back(i);
std::cout << *v[i].m_RandSid << std::endl;
std::cout << "Vector size = " << v.size()<< " Vector capacity = " << v.capacity() << std ::endl;
}
std::cout<<std::endl<<"--------------------------------------------------------"<<std::endl;
return 0;
}
when I run this program, I the following output:
inserting person #0
Vector size = 0 Vector capacity = 0
Person CTOR: 0
07QoUmgEe6
Vector size = 1 Vector capacity = 1
inserting person #1
Vector size = 1 Vector capacity = 1
Person CTOR: 1
Person CCTOR: 0
Person DTOR: 0
07QoUmgEe6
Vector size = 2 Vector capacity = 2
--------------------------------------------------------
Person DTOR: 0
free(): double free detected in tcache 2
I don't understand where else I perform another free :\
The other problem is that the string is randomized per execution and not per object,
If srand is performed on each execution, why all the string look the same ?
In your copy and move constructor you simply copy raw pointers, which makes 2 pointers to point to the same memory, and when both objects destroyed you get double deallocation:
Person(const Person & p)
{
std::cout << "\033[1;31mPerson CCTOR: " << p.m_Id << "\033[0m" << std::endl;
m_Id = p.m_Id;
m_RandSid = p.m_RandSid; // now both pointers point to the same memory
}
It is not clear why you need dynamically allocated string objects, you should just store objects by value, but if you do need that you should use smart pointers (either std::shared_ptr or std::unique_ptr depends of what ownership you need). That will not only make your problem disappear but you would not have to provide copy and move constructor manually, compiler generated ones would be sufficient.
Note, your class is also missing proper copy and move assignment operator, though it is not exposed in code shown it still violates the rule of three/five/zero and you may have problems with your code later.
Your copy constructor copies the pointer value, and should be doing a deep copy (allocate a new string). In a simple design like this I would avoid using new/free for the string.
You initialize (actually reset) rand with time with second precision - time(). Your app probably finishes in less than a second, hence the similar strings. Initialize rand only once, eg when starting the app.

Passing around an object in C++ by reference [duplicate]

This question already has answers here:
What are the differences between a pointer variable and a reference variable?
(44 answers)
Closed 9 years ago.
I have objects that I put into a std::vector. Later on I need to iterate through the vector and change some member variables in the objects in each position.
I think I want to pass the object once I have it by reference to a function to operate on it, but I seem to be getting an error:
Non-const lvalue reference to type 'Object' cannot bind to a value of unrelated type 'Object *'
Here is the general gist with code between omitted:
Object* o1 = Object::createWithLocation(p.x, p.y);
v.push_back(o1);
// later on
for (int f=0; f < v.size(); f++)
{
Object* obj1 = v.at(f);
addChild(h->createLayer(obj1), 3); // add the HUD
}
createLayer is defined at:
static PlantingHUD* createLayer(Object &o);
Can anyone explain my confusion between pointers and passing by reference? Do I have to do a cast of some sort?
static PlantingHUD* createLayer(Object &o);
this method need a reference to Object as the parameter,
but your input is a pointer.
Object* obj1 = v.at(f);
addChild(h->createLayer(obj1), 3); // add the HUD
That's the problem.
void foo(Object o)
Declares a function, foo, which will begin execution with a fresh, new, instance of class 'Object' called 'o'.
This is called "passing by value", but it's more accurately 'copying' because what foo receives is it's own, personal copy of the Object instances we call foo with. When "foo" ends, the "Object o" it knew, fed and put through school, will cease to be.
void foo(Object& o)
Declares a function, foo, which will begin executing with a reference to an existing instance of an 'Object', this reference will be called 'o'. If you poke or prod it, you will be changing the original.
This is called "pass by reference".
void foo(Object* o)
Declares a function, foo, which will begin executing with a variable, called "o", containing the address of what is supposed to be an instance of "Object". If you change this variable, by doing something like "o = nullptr", it will only affect the way things look inside foo. But if you send Samuel L Jackson to the address, he can deliver furious vengance that lasts beyond the lifetime of foo.
void foo(Object*& o)
Declares a function, foo, which will begin executing with a variable called "o", which is a reference to a pointer to an instance of object o - it's like an alias, except that without compiler optimization, it's actually implemented by the compiler using a sort of pointer.
Lets try these separately.
#include <iostream>
#include <cstdint>
struct Object
{
int m_i;
void event(const char* what, const char* where)
{
std::cout <<
what<< " " << (void*)this <<
" value " << m_i <<
" via " << where <<
std::endl;
}
// Construct an object with a specific value.
Object(int i) : m_i(i)
{
event("Constructed", "Operator(int i)");
}
// This is called the copy constructor, create one object from another.
Object(const Object& rhs) : m_i(rhs.m_i)
{
event("Constructed", "Operator(const Object&)");
}
// This is how to handle Object o1, o2; o1 = o2;
Object& operator=(const Object& rhs)
{
m_i = rhs.m_i;
event("Assigned", "operator=");
return *this;
}
// Handle destruction of an instance.
~Object() { event("Destructed", "~Object"); }
};
void foo1(Object o)
{
std::cout << "Entered foo1, my o has value " << o.m_i << std::endl;
// poke our local o
o.m_i += 42;
std::cout << "I changed o.m_i, it is " << o.m_i << std::endl;
}
void foo2(Object* o)
{
std::cout << "Foo2 starts with a pointer, it's value is " << (uintptr_t)o << std::endl;
std::cout << "That's an address: " << (void*)o << std::endl;
std::cout << "m_i of o has the value " << o->m_i << std::endl;
o->m_i += 42;
std::cout << "I've changed it tho, now it's " << o->m_i << std::endl;
}
void foo3(Object& o)
{
std::cout << "foo3 begins with a reference called o, " << std::endl <<
"which is sort of like a pointer but the compiler does some magic " << std::endl <<
"and we can use it like a local concrete object. " <<
std::endl <<
"Right now o.m_i is " << o.m_i <<
std::endl;
o.m_i += 42;
std::cout << "Only now, it is " << o.m_i << std::endl;
}
void foo4(Object*& o)
{
std::cout << "foo4 begins with a reference to a pointer, " << std::endl <<
"the pointer has the value " << (uintptr_t)o << " which is " <<
(void*)o <<
std::endl <<
"But the pointer points to an Object with m_i of " << o->m_i << std::endl <<
"which we accessed with '->' because the reference is to a pointer, " <<
"not to an Object." <<
std::endl;
o->m_i += 42;
std::cout << "I poked o's m_i and now it is " << o->m_i << std::endl;
// Now for something really dastardly.
o = new Object(999);
std::cout << "I just changed the local o to point to a new object, " <<
(uintptr_t)o << " or " << (void*)o << " with m_i " << o->m_i <<
std::endl;
}
int main()
{
std::cout << "Creating our first objects." << std::endl;
Object o1(100), o2(200);
std::cout << "Calling foo1 with o1" << std::endl;
foo1(o1);
std::cout << "back in main, o1.m_i is " << o1.m_i << std::endl;
std::cout << "Calling foo2 with &o1" << std::endl;
foo2(&o1);
std::cout << "back in main, o1.m_i is " << o1.m_i << std::endl;
std::cout << "Calling foo3(o2), which looks like the way we called foo1." << std::endl;
foo3(o2);
std::cout << "back in main, o2.m_i is " << o2.m_i << std::endl;
std::cout << "Creating our pointer." << std::endl;
Object* optr;
std::cout << "Setting it to point to 'o2'" << std::endl;
optr = &o2;
std::cout << "optr now has the value " << (uintptr_t)optr <<
" which is the address " << (void*)optr <<
" which points to an Object with m_i = " << optr->m_i <<
std::endl;
foo4(optr);
std::cout << "back in main, o2 has the value " << o2.m_i << std::endl <<
"and now optr has the value " << (uintptr_t)optr << std::endl <<
"and optr->m_i is now " << optr->m_i <<
std::endl;
if (optr != &o2)
delete optr; // otherwise we'd technically be leaking memory.
return 0;
}
Live demo on ideone.com.
Passing by Value
This term confuses people early in their C++ development because, in lay terms, it sounds like this is what "Object& foo" would do.
The term "pass by value" actually arises from what the language has to do to call such a function, to value-wise copy the whole of the original object/struct onto the stack or, in the case where a copy ctor is available, forward them to a value-wise constructor and recreate a copy of the original, value-by-value.
Pass-by-value should be used for most simple cases where you do not want side-effects on the values in your current scope from the function you are calling.
bool checkWidthdrawl(Dollars balance, Dollars amountToWithdraw)
{
// it's safe for me to change "balance" here because balance is mine
}
vs
bool checkWidthdrawl(Dollars& balance, Dollars amountToWithdraw)
{
balance -= amountToWithdraw;
if (balance < 0)
std::complaint << "My account seems to be missing $" << amountToWithdraw;
}
However, passing by reference can become expensive.
struct FourK { char a[1024], b[1024], c[1024], d[1024]; }
If you pass this around by value all day, you risk blowing up your stack at some point, as well as spending daft amounts of time copying all those bytes.
void foo(int i); // Unless you need to see the changes to i, this is perfectly fine.
void foo(FourK f); // Someone should hunt you down and yell "PEANUT" in your ear.
Passing by reference
References are really a contract over the pointer system that allow the language to ensure you're really talking about a concrete instance of an object, and thus allow you to refer to a pre-existing instance of a value outside of a function.
Of course, there are ways to break this, but the language tries very, very hard to make them difficult to do. For example, try adding this to the above code:
Object& makeObjectNotWar(int i)
{
Object thisObjectGoesAway(i);
return thisObjectGoesAway /*right about now*/;
}
You can also provide callers with an assurance that the function won't have any side effects on a variable with the "const" modifier.
void fooc(const Object& o)
{
o.m_i += 42; // Error
}
You can even use that within a function as a hint to yourself (and the compiler) that you don't want to accidentally change a value, here's a case where it can provide an optimization hint to the compiler:
std::vector<int> foo;
add1000valuesTo(foo);
const size_t fooSize = foo.size();
for (size_t i = 0; i < fooSize; ++i) {
// ... stuff you're sure won't decrease foo.size()
}
Without the const fooSize
for (size_t i = 0; i < foo.size(); ++i) {
The compiler has to start by assuming that "foo.size()" could be changed at any given iteration of the loop. It can probably figure out that it doesn't, but by giving it the hint, you've saved a little compile time, possibly improved your performance, and made it easier for a human to tell exactly what behavior you expected. Downside: If your loop does actually change the size of foo, you'll find out by bug reports :(
One last thing to know about pass-by-reference is that C++ references aren't protected or "ref counted". The language only promises that a reference will be valid for the duration of its scope, so long as you don't do anything stupid like, say, call something that deletes the object.
// Author intended this function to be called
// by the owner of a Dog.
void doneWithFoo(Dog& dog)
{
Dog* deadDog = &dog;
delete deadDog;
}
Rover& Babysitter::babysitDog(Dog& rover, int hours)
{
rover.feed(FeedType::Donut);
if (rover.pooped())
doneWithDog(rover);
// ...
return rover; // I have a bad feeling about this.
}
Obviously, you're not expecting "babysitDog" to result in the dog being disposed of. But bear in mind that because we passed in a reference, it to "babysitDog" that it's also gone from the caller too, and if that was using a reference... rover's dead, Dave, dead.
As with pointers, if you're going to store references beyond the scope in which you have access to them, then you become responsible for making sure the objects being referenced stick around or that the references are removed from the container before the objects do go away.

Destruction of an object when erasing it from std::map

I was curios if default destructor is called, when I'm removing an element from an std::map. Here is an example which I have made:
class CTestMap{
public:
CTestMap() {
std::cout << "default constructor called" << std::endl;
}
CTestMap(int id) {
std::cout << "created object: " << id << std::endl;
m_id = id;
}
~CTestMap() {
std::cout << "destroyed object: " << this->m_id << std::endl;
}
int get_id(){
return m_id;
}
int m_id;
};
int main(void){
std::map<int, CTestMap>m;
std::map<int, CTestMap>::iterator m_it;
std::cout << "created map " << std::endl;
CTestMap t1(1);
std::cout << "created test object: " << t1.get_id() << std::endl;
CTestMap t2(2);
std::cout << "created test object: " << t2.get_id() << std::endl;
CTestMap t3(3);
std::cout << "created test object: " << t3.get_id() << std::endl;
m[1] = t1;
m_it = m.find(1);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[2] = t2;
m_it = m.find(2);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[3] = t3;
m_it = m.find(3);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m_it = m.find(1);
std::cout << "will now erased test object: " << m_it->second.get_id() << std::endl;
m.erase(m.find(1));
std::cout << "erased test object: " << m[1].get_id() << std::endl;
m_it = m.find(1);
std::cout << "object shall no longer exist: " << m_it->second.get_id() << std::endl;
while(1);
return 0;
}
An here is the output:
./htest
created map
created object: 1
created test object: 1
created object: 2
created test object: 2
created object: 3
created test object: 3
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 1
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 2
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 3
will now erased test object: 1
destroyed object: 1
default constructor called
destroyed object: 158830600
destroyed object: 158830600
erased test object: 158830600
object shall no longer exist: 158830600
Questions are:
Why so many times default constructor is called, when I'm only
creating 3 objects using my own constructor ?
Can I, based on
this example say, that each time I'm erasing any object from the
std::map, its destructor is called ? Is this general behavior of a
std::map ? I could not find this information.
What if I'm storing pointers to objects (I'm creating them using 'new' operator) ? When then delete shall be called ?
std::map stores a copy of the object you insert. When the
object is removed, it is this copy which is destructed. So
after m[1] = t1;, there are two identical instances of
CTestMap: t1 and the one in the map.
Also: m[1] = t1; will first create a new entry in the map,
using the default constructor, and later assign t1 to it.
In general, if you want to trace instance lifetime like this,
you need provide a user defined copy constructor and assignment
operator which trace as well. And you probably want to output
the this pointer in all of the traces. (Another technique
would be to dote each object with an immutable unique
identifier:
#define TRACE(m) std::cout << #m << '(' << m_objectId << ')' << std::endl
static int currentObjectId = 0;
class TestMap
{
int m_id;
int const m_objectId;
public:
TestMap()
: m_id( 0 )
, m_objectId( ++ currentObjectId )
{
TRACE(DFLT);
}
TestMap( int id )
: m_id( id )
, m_objectId( ++ currentObjectId )
{
TRACE(CTOR);
}
TestMap( TestMap const& other )
: m_id( other.m_id )
, m_objectId( ++ currentObjectId )
{
TRACE(COPY);
}
~TestMap()
{
TRACE(DTOR);
}
TestMap& operator=( TestMap const& other )
{
m_id = other.m_id;
TRACE(ASGN);
return *this;
}
};
You might want to add additional information (like m_id) to
the trace as well.
Also: your last output invokes undefined behavior. After
m.find(i), you should check first that the iterator hasn't
returned m.end(). If it has, dereferencing isn't allowed. So
your test output should be something like:
void
testOutput( std::map<int, TestMap> const& m, int i )
{
std::map<int, TestMap>::const_iterator entry = m.find( i );
if ( entry == m.end() ) {
std::cout << "no object at " << i << std::endl;
} else {
std::out << "object " << entry->second.m_id << " at " << i << std::endl;
}
}
(Finally: I think Microsoft has preempted the C prefix for
classes, so you should avoid it. If you want a prefix, choose
something else, to avoid confusion.)
If you store an actual object (rather than a reference or pointer), yes, the object gets destroyed when you erase it.
If you store pointers or references, then the object is not destroyed, and delete is not called on a pointer. If you want that to happen automatically, you should use a smart pointer (e.g. unique_ptr or shared_ptr depending on what behaviour you want).
If you don't use smart pointers, then you will need to take pointer stored, and delete the object yourself (after using erase to remove the element from the map).
Your default constructor is called a fourth time, because m[1] in
std::cout << "erased test object: " << m[1].get_id() << std::endl;
will construct a new object with key "1". This is because such an element doesn't exist in the map yet – otherwise it would just return that already existing object. (It did exist before, but you erased it in the line above! ;])

How can I create objects while adding them into a vector?

I have a C++ vector. I want the vector to hold a variable number of objects.
Visual Studio 2012 is giving me an error:
Error: type name is not allowed
From this C++ code:
#include <iostream>
#include <vector>
using namespace std;
class testObject{
private:
int someInt;
public:
testObject(int a){ someInt=a; }
void show() { cout<<someInt<<endl; }
};
int main()
{
vector<testObject> testVector;
cout << "Initial size: " << testVector.size() <<endl;
for ( int i = 0; i < 3; i++ )
testVector.push_back(testObject(3));
cout << "New size: " << testVector.size() << endl;
for ( int j = 0; j < 3; j++ )
testVector[ j ].show();
system("pause");
}
But here's another sample of code that looks the same but it's not working.
void Dealer::setNumberOfPlayers( const int tNumber )
{
for ( int i = 0; i < tNumber; i++ )
vectorOfGamers.push_back(Player); // Player is a class that I created
}
Can I create vector to hold objects of Dealer, Bot and Player at the same time? How do I do that? As I know, all objects in vector should be of one type.
To answer the first part of your question, you must create an object of type Player before you can use it. When you say push_back(Player), it means "add the Player class to the vector", not "add an object of type Player to the vector" (which is what you meant).
You can create the object on the stack like this:
Player player;
vectorOfGamers.push_back(player); // <-- name of variable, not type
Or you can even create a temporary object inline and push that (it gets copied when it's put in the vector):
vectorOfGamers.push_back(Player()); // <-- parentheses create a "temporary"
To answer the second part, you can create a vector of the base type, which will allow you to push back objects of any subtype; however, this won't work as expected:
vector<Gamer> gamers;
gamers.push_back(Dealer()); // Doesn't work properly!
since when the dealer object is put into the vector, it gets copied as a Gamer object -- this means only the Gamer part is copied effectively "slicing" the object. You can use pointers, however, since then only the pointer would get copied, and the object is never sliced:
vector<Gamer*> gamers;
gamers.push_back(new Dealer()); // <-- Allocate on heap with `new`, since we
// want the object to persist while it's
// pointed to
Question 1:
vectorOfGamers.push_back(Player)
This is problematic because you cannot directly push a class name into a vector.
You can either push an object of class into the vector or push reference or pointer to class type into the vector. For example:
vectorOfGamers.push_back(Player(name, id))
//^^assuming name and id are parameters to the vector, call Player constructor
//^^In other words, push `instance` of Player class into vector
Question 2:
These 3 classes derives from Gamer. Can I create vector to hold objects of Dealer, Bot and Player at the same time? How do I do that?
Yes you can. You can create a vector of pointers that points to the base class Gamer.
A good choice is to use a vector of smart_pointer, therefore, you do not need to manage pointer memory by yourself. Since the other three classes are derived from Gamer, based on polymorphism, you can assign derived class objects to base class pointers. You may find more information from this post: std::vector of objects / pointers / smart pointers to pass objects (buss error: 10)?
You cannot insert a class into a vector, you can insert an object (provided that it is of the proper type or convertible) of a class though.
If the type Player has a default constructor, you can create a temporary object by doing Player(), and that should work for your case:
vectorOfGamers.push_back(Player());
I know the thread is already all, but as I was checking through I've come up with a solution (code listed below). Hope it can help.
#include <iostream>
#include <vector>
class Box
{
public:
static int BoxesTotal;
static int BoxesEver;
int Id;
Box()
{
++BoxesTotal;
++BoxesEver;
Id = BoxesEver;
std::cout << "Box (" << Id << "/" << BoxesTotal << "/" << BoxesEver << ") initialized." << std::endl;
}
~Box()
{
std::cout << "Box (" << Id << "/" << BoxesTotal << "/" << BoxesEver << ") ended." << std::endl;
--BoxesTotal;
}
};
int Box::BoxesTotal = 0;
int Box::BoxesEver = 0;
int main(int argc, char* argv[])
{
std::cout << "Objects (Boxes) example." << std::endl;
std::cout << "------------------------" << std::endl;
std::vector <Box*> BoxesTab;
Box* Indicator;
for (int i = 1; i<4; ++i)
{
std::cout << "i = " << i << ":" << std::endl;
Box* Indicator = new(Box);
BoxesTab.push_back(Indicator);
std::cout << "Adres Blowera: " << BoxesTab[i-1] << std::endl;
}
std::cout << "Summary" << std::endl;
std::cout << "-------" << std::endl;
for (int i=0; i<3; ++i)
{
std::cout << "Adres Blowera: " << BoxesTab[i] << std::endl;
}
std::cout << "Deleting" << std::endl;
std::cout << "--------" << std::endl;
for (int i=0; i<3; ++i)
{
std::cout << "Deleting Box: " << i+1 << " (" << BoxesTab[i] << ") " << std::endl;
Indicator = (BoxesTab[i]);
delete(Indicator);
}
return 0;
}
And the result it produces is:
Objects (Boxes) example.
------------------------
i = 1:
Box (1/1/1) initialized.
Adres Blowera: 0xdf8ca0
i = 2:
Box (2/2/2) initialized.
Adres Blowera: 0xdf8ce0
i = 3:
Box (3/3/3) initialized.
Adres Blowera: 0xdf8cc0
Summary
-------
Adres Blowera: 0xdf8ca0
Adres Blowera: 0xdf8ce0
Adres Blowera: 0xdf8cc0
Deleting
--------
Deleting Box: 1 (0xdf8ca0)
Box (1/3/3) ended.
Deleting Box: 2 (0xdf8ce0)
Box (2/2/3) ended.
Deleting Box: 3 (0xdf8cc0)
Box (3/1/3) ended.
// create a vector of unknown players.
std::vector<player> players;
// resize said vector to only contain 6 players.
players.resize(6);
Values are always initialized, so a vector of 6 players is a vector of 6 valid player objects.
As for the second part, you need to use pointers.
Instantiating c++ interface as a child class