Templated classes

closed account (jvqpDjzh)
//Hello! How can I declare (and create) correctly a pointer to a templated class?
//And how to declare a pointer to various objects?

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
template <class t>//templated class
class Square
{
    public:
    t side;
    //inline constructor
    Square(t side){ this->side = side; }

    ~Square() { }

    t getSide();
};


1
2
3
4
/*
template <class t>
t Square<t>::getSide() { return side; }
*/


1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
    //Is this correct?//this seems to work
    Square <double>* sqr = new Square<double> (3.14);
    cout << sqr->getSide() << endl 
  
    Square <double>* sqrX = new Square<double> [4];
   //this not works, because I dont' have the default constructor
   //but I would like to use the current constructor I've defined.
   //I mean, I would like to call the constructor I've defined to initialize all the 4 objects
 
    return 0;
}


//Thank you in advance.
Last edited on
1
2
3
4
5
6
Square<double> sqr(3.14);

std::vector< Square<double> > sqrX;
sqrX.reserve(4);
//when you know how you want to construct the object
sqrX.push_back( Square<double>(2.79) );
closed account (jvqpDjzh)
But shouldn't sqrX.push_back () just append 1 element at the end of the sqrX ?
So actually we have just a vector with one templated class?! To have 4 or 5 or whatever we want, we have to use a loop!

Is it necessary to reserve the area? (because I have just seen that push_back() reallocates memory automatically...)

So the code could be:
1
2
3
4
5
    int LEN = 5;
    vector< Square<double> > sqrX;
    //sqrX.reserve(5);//it s not necessary 
    for (int i=0; i< LEN; i++)
        sqrX.push_back( Square <double> (2.79) );
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <vector>
#include <new>

template <class t>//templated class
class Square
{
public:
    t side;
    //inline constructor
    Square(t side){ this->side = side; }

    ~Square() { }

    t getSide();
};


int main()
{
    const unsigned num_elements = 4;

    {
        // manually:
        void* raw_memory = operator new(sizeof(Square<double>) * num_elements);
        Square<double>* sqr = static_cast<Square<double>*>(raw_memory);

        // construct each of the 4 squares:
        for (unsigned i = 0; i < num_elements; ++i)
            new (sqr + i) Square<double>(i*3.14);

        // use the Squares here

        // then, what was constructed must be destructed:
        for (unsigned i = 0; i < num_elements; ++i)
            (sqr + i)->~Square<double>();

        // and the memory deallocated.
        operator delete(sqr);
    }

    //using std::vector:
    {
        std::vector<Square<double>> sqr;
        for (unsigned i = 0; i < num_elements; ++i)
            sqr.emplace_back(i*3.14);

        // use the squares here...

        // then the objects are automatically destructed and
        // memory freed when sqr goes out of scope.
    }
}


http://ideone.com/69kk62

You should probably prefer the vector.
Last edited on
closed account (jvqpDjzh)
Thank you! Yes, I find that vector is a nice and useful templated class and a good header.

Why it is necessary to use the keyword "operator" before new and delete? In the first case we could replace the "operator new" simply with malloc, right?

I can't really understand the syntax at line 29:
new (sqr + i) Square<double>(i*3.14);


Trying to understand things...
You have to number the objects you are allocating with (sqr + i) ? Would you do the same thing with "normal" classes, right?

outside our dare main
1
2
3
4
5
6
7
8
9
class Square
{
    int side;
    //...
public:
    ~Square(){};
    Square(int side = 1) { //... }
};

in main function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    int num_objs = 4;
    void* raw_memory = operator new ( sizeof(Square)* num_objs );
    Square* sqr = static_cast<Square*>(raw_memory);

    for(int i = 0; i<num_objs; i++)
        new (sqr + i) Square (i);//I don't understand very well this syntax...

    //do what I want...

    for(int i = 0; i<num_objs; i++)
        (sqr + i)->~Square();

    operator delete(sqr);//Are we using "operator"+delete like free(sqr)?
    //shoudn't we deallocate also the memory for raw_memory?
    //operator delete(raw_memory); 



See: http://eli.thegreenplace.net/2011/02/17/the-many-faces-of-operator-new-in-c/

You have to number the objects you are allocating with (sqr + i) ? Would you do the same thing with "normal" classes, right?

That is simple pointer arithmetic. I could've written: new (&sqr[i]) Square(i*3.14); The second question makes no sense to me.


1
2
    //shoudn't we deallocate also the memory for raw_memory?
    //operator delete(raw_memory);  

No. sqr and raw_memory point to the same piece of memory. You don't want to free the same piece of memory twice, however we could've used operator delete on raw_memory instead of sqr.
@cire: i don't understand why you're using operator new and operator delete and not just new and delete?
chipp wrote:
@cire: i don't understand why you're using operator new and operator delete and not just new and delete?

Because they wouldn't work in this case without modifying the Square class. See the OP.

Of course, in C++11, we could do this:

1
2
3
4
5
6
7
8
    {
        // C++11 alternate manual method:
        Square<double>* sqr = new Square<double>[4] { 3.14, 6.28, 9.42, 12.56 };

        // use the Squares here

        delete [] sqr;
    }


which, of course, can also be done with a vector without the need for the delete.
Last edited on
closed account (jvqpDjzh)

That is simple pointer arithmetic. I could've written: new (&sqr[i]) Square(i * 3.14);

That's is a simple pointer arithmetic for you, that have used them for a while!
Why did you put "&" before sqr (&sqr[i])?

Anyway, I was not asking about pointers arithmetic, I was asking why did you put a pointer before a constructor call?


The second question makes no sense to me.
???

Last edited on
zwiluwu wrote:
Why did you put "&" before sqr (&sqr[i])?
zwiluwu wrote:
Anyway, I was not asking about pointers arithmetic, I was asking why did you put a pointer before a constructor call?

A placement new expression requires a pointer which is the address where the object to be constructed will reside.
Last edited on
closed account (jvqpDjzh)
A placement new expression requires a pointer which is the address where the object to be constructed will reside.


So for a non-templated class would be the same:
1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo
{
    //...
};

int main()
{
    Foo* f1 = new Foo[5];
    for (int i=0; i<5; i++)
        new (f1+i) Foo ();//or new (&f1[i]) Foo();
        
    return 0;
}


Anyway, thanks!
In the code above, the objects are constructed twice, leading to undefined behavior. Don't use new[] and follow it up with placement new.
closed account (jvqpDjzh)
But if I use new Foo[5]; I am not calling the singles constructors (just allocating memory for 5 constructors, right?)

And if we wanted to initialize the objects (with another constructor)? Should we do like your first example: allocating memory first to all the objects and then create the objects singularly?
Something like this?
1
2
3
4
5
6
int num_objs = 5;

Foo* f1 = (Foo*)malloc( sizeof(Foo)* num_objs); 

for (int i=0; i<5; i++)
     new (f1 + i) Foo(i);


its the same error?
Last edited on
Foo* f1 = new Foo[5];
would allocate memory for the objects and construct them

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int n = 42;
std::allocator<Foo> alloc;
//reserving memory
std::allocator<Foo>::pointer ptr = alloc.allocate(n);

//constructing objects
for(int K=0; K<n; ++K)
	alloc.construct( ptr+K, K ); //c++11
	//alloc.construct( ptr+K, Foo(K) ); //c++98

//destroying objects
for(int K=0; K<n; ++K)
	alloc.destroy( ptr+K );

//releasing memory
alloc.deallocate( ptr, n );
Last edited on
zwiluwu You should check out this link on operator new. http://www.cplusplus.com/reference/new/operator%20new/?kw=operator%20new
But if I use new Foo[5]; I am not calling the singles constructors (just allocating memory for 5 constructors, right?)

No, not right. The expression new Foo[5]; allocates space for 5 Foo objects and default constructs them.


And if we wanted to initialize the objects (with another constructor)? Should we do like your first example: allocating memory first to all the objects and then create the objects singularly?
Something like this?

Right now, I think you should move on to other things and come back to this when you've had more exposure to the language. This isn't the easiest facet of the language to understand. (And, no, that code does not cause undefined behavior like the previous did.)

Use containers.
closed account (jvqpDjzh)
I would like to understand things. This is not difficult, I just have little experience and have read just a few things about the topic. You don't have to get angry! I don't have to use containers and give up to understand things more complicated (to be ignorant).

Ok, so with the expression new Foo[5] we are of course allocating memory for 5 objects of type Foo and we are also initializing them, calling the default constructor, as you said.

So the difference between this code:
1
2
3
Foo* f1 = (Foo*)malloc( sizeof(Foo)* num_objs); 
for (int i=0; i<5; i++)
     new (f1 + i) Foo(i);

and this other:
1
2
3
    Foo* f1 = new Foo[5];
    for (int i=0; i<5; i++)
        new (f1+i) Foo ();//or new (&f1[i]) Foo(); 

is that the first case we are not calling, with the expression:
Foo* f1 = (Foo*)malloc( sizeof(Foo)* num_objs);
, the constructors for the single objects of type Foo, we are just ofc allocating memory, so there's no undefined behavior, instead in the second case we call the objects constructors twice.

So could we call another constructor with the first piece of code?
1
2
3
Foo* f1 = (Foo*)malloc( sizeof(Foo)* num_objs); 
for (int i=0; i<5; i++)
new (f1 + i) Foo(/*another constuctor*/);

Last edited on
zwiluwu wrote:
You don't have to get angry! I don't have to use containers and give up to understand things more complicated (to be ignorant).

What makes you think using containers means you're giving up or will remain ignorant? I say you need to come back to this later because you keep asking the same question over and over.

zwiluwu wrote:
So could we call another constructor with the first piece of code?

Yes. See the very first piece of code I posted. That is what started this entire line of questioning, remember?
closed account (jvqpDjzh)
I am not asking the same thing again and again, if I ask things similar between them it's because you can't respond unambiguously and completely!!!

Yes. See the very first piece of code I posted. That is what started this entire line of questioning, remember?
Dude, the first piece of code you posted was about templated classes, I remembered exactly from where this all began. Then I began to ask about non-templated classes, remember? You couldn't distinguish things, even if things are equal, you have to specify that they are! If you didn't understand my questions, it's another discussion!
Last edited on
Topic archived. No new replies allowed.