Create an array of class objs - c++

Consider following class
class test
{
public:
test(int x){ cout<< "test \n"; }
};
Now I want to create array of 50 objects of class test . I cannot change class test.
Objects can be created on heap or stack.
Creating objs on stack is not possible in this case since we dont have default constructor in class
test objs(1)[50]; /// Error...
Now we may think of creating objs on heap like this..
test ** objs = NULL;
objs = (test **) malloc( 50 * sizeof (test *));
for (int i =0; i<50 ; ++ i)
{
objs[i] = new test(1);
}
I dont want to use malloc .Is there any other way??
If you guys can think of some more solutions , please post them...

You cannot create an array of objects, as in Foo foo [N], without a default constructor. It's part of the language spec.
Either do:
test * objs [50];
for() objs[i] = new test(1).
You don't need malloc(). You can just declare an array of pointers.
c++decl> explain int * objs [50]
declare objs as array 50 of pointer to int
But you probably ought to have some sort of automatic RAII-type destruction attached.
OR subclass test publicly:
class TempTest : public test
{
public:
TempTest() : test(1) {}
TempTest(int x) : test(x) {}
TempTest(const test & theTest ) : test(theTest) {}
TempTest(const TempTest & theTest ) : test(theTest) {}
test & operator=( const test & theTest ) { return test::operator=(theTest); }
test & operator=( const TempTest & theTest ) { return test::operator=(theTest); }
virtual ~TempTest() {}
};
and then:
TempTest array[50];
You can treat every TempTest object as a test object.
Note: operator=() & copy constructor are not inherited, so respecify as necessary.

Why do you need array?
std::vector<test*> v(50);
Or as #j_random_hacker suggested in the comments:
std::vector<test> v(50, test(1));
An example:
/** g++ -Wall -o vector_test *.cpp && vector_test */
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
struct Test {
int value;
Test(int x) : value(x)
{
std::cout << "Test(" << value << ")" << " ";
}
operator int() const
{
std::cout << "int(" << value << ")" << " ";
return value;
}
};
int main()
{
using namespace std;
vector<Test> v(5, Test(1));
cout << endl;
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
v[1] = 2;
v[2].value = 3;
cout << endl;
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
Output:
Test(1)
int(1) 1 int(1) 1 int(1) 1 int(1) 1 int(1) 1
Test(2)
int(1) 1 int(2) 2 int(3) 3 int(1) 1 int(1) 1

Contrary to what many people believe, you can actually create an array of objects that do not have a default constructor. What you cannot do is make it use a set of arguments for all constructor invokations. You just have to initialize all elements of it. That is, you can do the following:
#define PRINTT(z, n, initializer) initializer
test objs[50] = {
BOOST_PP_ENUM(50, PRINTT, 1) // yields 1, 1, 1, .... 1
};
#undef PRINTT
That will initialize all 50 elements with 1. boost::pp is used to print a 1 50 times in a row automatically.

I think that other responders are treating this question too literally.
If all you really want to do is make a "group" of 50 objects that you can treat as an array, then by far the easiest and most maintainable way of accomplishing what you're trying to do is:
std::vector<test> objs(50, test(1));
This declares a vector of 50 objects, each of which is a copy of test(1). A vector is basically a C++ growable array; although you may not need the growability, the fact that it can be called with a 2-arg constructor that copy-constructs each element is useful here.
You can use this more-or-less exactly like an array -- e.g. the 5th element is objs[4]. Performance is the same too -- the C++ standard guarantees that internally the elements are stored in a contiguous array.

You don't need malloc(). You can use new for the array of pointers, too:
test **objs = new test* [50];

Boost's Pointer Container library might come to rescue here. With boost::ptr_vector<T> you can hold a list of heap-allocated objects which can be even polymorphic (virtual functions), which isn't possible with simply std::vector<T>.
Unlike std::vector<T>, the objects won't be stored in subsequential memory addresses. Things like resizing the container however will be faster because the elements will keep their original memory addresses. The best bonus is, you don't need to call delete yourself: the contained objects will be destroyed when the ptr_vector goes out of scope. Example:
#include <boost/ptr_vector.hpp>
#include <iostream>
class test() {
protected:
int const i;
public:
explicit test(int i) : i(i) {}
virtual void who_am_i() const { std::cout << "I am test " << i << std::endl; }
};
class special_test : public test {
public:
explicit special_test(int i) : test(i) {}
virtual void who_am_i() const { std::cout << "I am special_test " << i << std::endl; }
};
int main() {
boost::ptr_vector<test> objs;
for (int i=0; i<50; ++i)
objs.push_back(new test(i)); // NB: constructing to heap here!
objs.push_back(new special_test(123)); // objs can also hold inherited classes
objs[13].who_am_i(); // outputs: I am test 13
objs[50].who_am_i(); // outputs: I am special_test 123
} // all created objects are automatically destroyed here

Related

std::vector with elements allocated on the heap - do I need rule of 5?

If I have a class with members like this:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?
EDIT:
The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.
You need to implement the copy constructor, copy assignment and destructor.
Additionally, consider changing your vector declaration from
std::vector<MyStruct*> my_vector;
to
std::vector<std::unique_ptr<MyStruct>> my_vector;
so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.
No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:
Store MyStruct by value.
Store std::unique_ptr<MyStruct>.
Store std::shared_ptr<MyStruct>.
Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.

Copying an array

I am trying to copy an array.
class Myobject
{
int nb;
string name;
Myobject* next;
Myobject(int nb, string name) {this->name=name; this->nb=nb; this->next=NULL;}
};
Myobject **array;
array= new Myobject*[100];
how can I make a deep copy of the Myobject ** and thus be able to modify one of the instances.
If you want to be up to date, use RAII for which C++ is really good for.
#include <vector>
#include <memory>
#include <string>
#include <iostream>
struct Myobject : std::enable_shared_from_this< Myobject >
{
int nb;
std::string name;
std::shared_ptr<Myobject> next;
Myobject(int nb, std::string name) { this->name=name; this->nb=nb; }
~Myobject() { std::cout << "deleting " << nb << " " << name << std::endl; }
};
int main() {
std::vector< std::shared_ptr< Myobject > > arr;
arr.push_back(std::make_shared< Myobject >(1,"first"));
arr.push_back(std::make_shared< Myobject >(2,"second"));
for (auto obj: arr) {
std::cout << obj->nb << " " << obj->name << std::endl;
}
arr[0]->next = arr[1];
};
outputting
1 first
2 second
deleting 1 first
deleting 2 second
and you don't need to care much about memory management at first. Your example without proper care would generate memory leaks.
Update: forgot to mention, if you have circular references, beware, you might get memory leaks using shared_ptrs as well. If that should be the case, you might avoid that by switching to weak_ptrs → std::weak_ptr
You may add this (deep)-copy constructor:
Myobject(const Myobject& rhs) :
nb(rhs.nb),
name(rhs.name),
next(rhs.next == NULL ? NULL : new Myobject(*rhs.next))
{}
You will probably have to add a correct destrutor to avoid memory leak...
If possible, I suggest to use std::list<Myobject> instead
Allocate array and loop to copy.
NewMyobject **newarray = new Myobject*[100];
for (int i = 0 ; i < 100; ++i)
newarray[i] = new MyObject(array[i]);
Object must have a copy constructor.

C++: track access to array element

I have a class that I use to keep track of the values assumed by a variable. I implemented it by overloading operator=.
Usage example:
myType var0;
var0 = 1;
var0 = 3;
generates on stdout:
1
3
This works fine with variables, but not with arrays. How can I extend this feature?
One way would be overloading the [] operator to return a "proxy" - an object that references your variable, and overloads the = operator to do the tracking.
Here is a sample implementation:
#include <iostream>
using namespace std;
struct myArray;
class proxy {
myArray &array;
int index;
public:
proxy(myArray &_array, int _index)
: array(_array)
, index(_index) {
}
proxy& operator=(int value);
operator int() const;
};
struct myArray {
int data[100];
proxy operator[](int index) {
return proxy(*this, index);
}
};
proxy& proxy::operator=(int value) {
cout << "Asigning " << value << " to element " << index << endl;
array.data[index] = value;
return *this;
}
proxy::operator int() const {
cout << "Reading element at " << index << endl;
array.data[index];
}
int main() {
myArray a;
a[5] = 123;
a[8] = 321;
int x = a[5];
return 0;
}
This prints
Asigning 123 to element 5
Asigning 321 to element 8
Reading element at 5
What you want to do is to use a proxy class for your array and on that class define an operator[] function. Much like how std::vector does it.
You would trace when a non-const reference is produced to an array element. I think that you'd have to assume it was about to be written to. You would make the array out of your existing class so that you'd see the actual write.
The output might look like:
ref to element 32: write 1
Or however you would like it.
Well, arrays don't support operator= anyway, so that is not a real a problem. You can assign to individual array elements of course, but that's already covered by your existing operator=.
You could create a MyArrayType that overloads the [] operator to store the values internally within an array of MyTypes

complex template parameter type for C++ STL set

I'm implementing an STL set with a complex template parameter type. When inserting in to the set, I want the set to use the less-than operator I've defined for my type. I also want to minimize the quantity of object instantiations of my type. It seems I can't have both.
I've got two minimal examples below, each uses the same C++ class.
#include <iostream>
#include <set>
using namespace std;
class Foo {
public:
Foo(int z);
Foo(const Foo &z);
bool operator<(const Foo &rhs) const;
int a;
};
Foo::Foo(int z)
{
cout << "cons" << endl;
a = z;
}
Foo::Foo(const Foo &z)
{
cout << "copy cons" << endl;
a = z.a;
}
bool
Foo::operator<(const Foo &rhs) const
{
cout << "less than" << endl;
return a < rhs.a;
}
Here's my first main():
int
main(void)
{
set<Foo> s;
s.insert(*new Foo(1));
s.insert(*new Foo(2));
s.insert(*new Foo(1));
cout << "size: " << s.size() << endl;
return 0;
}
That's great because it uses the less-than I've defined for my class, and thus the size of the set is correctly two. But it's bad because every insertion in to the set requires the instantiation of two objects (constructor, copy constructor).
$ ./a.out
cons
copy cons
cons
less than
less than
less than
copy cons
cons
less than
less than
less than
size: 2
Here's my second main():
int
main(void)
{
set<Foo *> s;
s.insert(new Foo(1));
s.insert(new Foo(2));
s.insert(new Foo(1));
cout << "size: " << s.size() << endl;
return 0;
}
That's great because an insertion requires just one object instantiation. But it's bad because it's really a set of pointers, and thus the uniqueness of set members is gone as far as my type is concerned.
$ ./a.out
cons
cons
cons
size: 3
I'm hoping there's some bit of information I'm missing. Is it possible for me to have both minimal object instantiations and appropriate sorting?
You are getting a copy from this: *new Foo(1).
Create this struct:
template<typename T>
struct PtrLess
{
bool operator()(const T *a, const T *b) const
{
return *a < *b;
}
};
Make the map look like set<Foo*, PtrLess<Foo>> s; and then add Foo's like s.insert(new Foo(1));
Note the *
Otherwise, when the map creates a container for the Foo item, since it is allocated within the foo containers definition, the map has to copy the supplied value into its internal Foo object.
Standard containers store a copy of the items that are added. If you want your set to store objects, rather than pointers you should simply do the following, otherwise you're creating a memory leak, since the objects allocated via new are never free'd via a corresponding delete.
int main()
{
set<Foo> s;
s.insert(Foo(1));
s.insert(Foo(2));
s.insert(Foo(1));
cout << "size: " << s.size() << endl;
return 0;
}
If you want to minimise the number of temporary objects instantiated, just use a single temporary:
int main()
{
set<Foo> s;
Foo temp(1);
s.insert(temp);
temp.a = 2;
s.insert(temp);
temp.a = 1;
s.insert(temp);
cout << "size: " << s.size() << endl;
return 0;
}
The output for this snippet (via ideone) is:
cons
copy cons
less than
less than
less than
copy cons
less than
less than
less than
size: 2
Generally, I would prefer to store the actual objects in a set<Foo> rather than pointers to objects in a set<Foo*>, since there can be no problems with object ownership (who/when new and delete need to be called), the total amount of memory allocated is smaller (for N items you need N*sizeof(Foo) rather than N*(sizeof(Foo) + sizeof(Foo*)) bytes) and data access could typically be expected to be faster (since there's no extra pointer indirection).
Hope this helps.
This is an extension to #Mranz's answer. Instead of dealing with raw pointers, put the pointers in an std::unique_ptr
#include <memory>
using namespace std;
template<typename T>
struct PtrLess
{
bool operator()(const T& a, const T& b) const
{
return *a < *b;
}
};
int
main(void)
{
set<unique_ptr<Foo>, PtrLess<unique_ptr<Foo>>> s;
s.insert(unique_ptr<Foo>(new Foo(1)));
s.insert(unique_ptr<Foo>(new Foo(2)));
s.insert(unique_ptr<Foo>(new Foo(1)));
cout << "size: " << s.size() << endl;
return 0;
}

Why aren't these shared_ptrs pointing to the same container?

I have a class Model:
class Model
{
...
boost::shared_ptr<Deck> _deck;
boost::shared_ptr<CardStack> _stack[22];
};
Deck inherits from CardStack.
I tried to make _stack[0] point to the same thing that _deck points to by going:
{
_deck = boost::shared_ptr<Deck>(new Deck());
_stack[0] = _deck;
}
It seems that the assignment to _deck of _stack[0] results in a copy of _deck being made. (I know this because modifications to _stack[0] do not result in modifications to _deck.) How can I get them to point to the same thing?
Ok - no copy constructor is being called. I have verified this by implementing it and seeing if it gets called - it doesn't.
However - I have a function that operates on CardStack objects:
void TransferSingleCard(CardStack & src, CardStack & dst, Face f)
{
if( !src._cards.empty() )
{
src._cards.back().SetFace(f);
dst.PushCard(src._cards.back());
src._cards.pop_back();
}
}
Now - when I call:
{
TransferSingleCard(*_stack[DECK], _someotherplace, FACEDOWN);
std::cout << *_stack[DECK];
std::cout << *_deck;
}
I get this output (where std::cout on a CardStack will print out the size of that stack):
Num(103) TOP
Num(104) TOP
... so I've concluded (incorrectly?) that _stack[DECK] points to something different.
The Deck
class Deck : public CardStack
{
public:
Deck(int numsuits=2, StackIndex index = NO_SUCH_STACK );
Deck::Deck( const Deck & d);
int DealsLeft() const;
void RecalcDealsLeft();
private:
int _dealsleft;
};
Not clear what you are asking about - consider this code:
#include <iostream>
#include "boost/shared_ptr.hpp"
using namespace std;
struct A {
virtual ~A() {
cout << "destroyed" << endl;
}
};
struct B : public A {
};
int main() {
boost::shared_ptr<B> b( new B );
boost::shared_ptr<A> a;
a = b;
}
Only one "destroy" message appears, indicating that no copy has been made.
This example - derives from #Neil's answer, tries to emulate what you say is happening. Could you check that it works as expected (A and B have the same count) on your system.
Then we could try and modify this code or your code until they match.
#include <boost/shared_ptr.hpp>
#include <iostream>
class A {
public:
virtual ~A()
{
std::cerr << "Delete A" << std::endl;
}
int _count;
void decrement()
{
_count --;
}
};
class B : public A {
public:
virtual ~B()
{
std::cerr << "Delete B" << std::endl;
}
};
int main()
{
boost::shared_ptr<B> b(new B);
b->_count = 104;
boost::shared_ptr<A> a;
a = b;
a->decrement();
std::cerr << "A:" << a->_count << std::endl;
std::cerr << "B:" << b->_count << std::endl;
return 0;
}
EDIT:
So from the comment, we know the original pointers are correct, so now we need to trace.
Either:
log pointers to see when they change.
Use watchpoints in a debugger to see when the pointer changes.
Use a third shared pointer to see which pointer is changed.
Introduce a function that changes both pointers at the same time.
I think the problem is that you're assigning between different types here. boost::shared_ptr is a template and templates are not polymorphic even if the type in them is. So what's happening is that your compiler sees the assignment from boost::shared_ptr<Deck> to boost::shared_ptr<CardStack> and notices that it can make the assignment by calling the copy constructor for CardStack to duplicate the Deck object.
I think what you want the assignment to look like is something like this:
_stack[0] = boost::static_pointer_cast<CardStack>(_deck);
Which will do the conversion the way you expect it to.
I think you may want shared_array for _stack . . . Take a look at the documentation on shared_ptr;from boost.org, specifically:
http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm
"Normally, a shared_ptr cannot
correctly hold a pointer to a
dynamically allocated array. See
shared_array for that usage."
Also, be aware of the T* get() function (not to be used without good reason) which returns the raw pointer being held by the managed pointer (shared_ptr in this case).