Template And Arrays

Discussion in 'C++' started by Marcelo De Brito, May 26, 2009.

  1. Hi!

    I have created a template in which there is a generic vector/array
    that can hold any type defined by the programmer or built-in types.
    When I define the vector/array using built-in types (int, double,
    etc.), I must insert data of the respective type in it. But when I
    define the array using a programmer defined type (e.g., a class), I
    can access the class' members even though I did not insert any object
    in it! See the lines of code below for a better explanation.

    class B { //Programmer defined type.
    public:
    B() {};
    B(int idd) : id(idd) {};
    B(const B&) {};
    virtual ~B() {};
    void setid(int idd) {id = idd;}
    void dummy() {cout << "B::dummy()" << " " << "id = " << id <<
    endl;}
    private:
    int id;
    };

    template <class T, int size = 10>
    class D1 {
    public:
    D1() : index(0) {};
    D1(const D1&) {};
    virtual ~D1() {};
    T vt[size];
    void push(T* i) {
    vt[index] = *i;
    index++;
    }
    void exvet() {
    for(int i = 0; i<index; i++)
    cout << "vt[" << i << "] = " << vt << endl;
    }
    void vetsize() {cout << size << endl;}
    private:
    int index;

    };

    int main()
    {
    D1<int, 5> od4; //First with int.

    for(int i = 0; i<5; i++)
    od4.push(&i); //<- Inserting ints in the array. Fine.

    od4.exvet(); //<- Shows the ints int the array, Fine too.

    D1<B, 10> od5; //Now with the programmer defined type.

    for(int i = 0; i<10; i++)
    od5.vt.dummy(); //<- !!!!!!!HERE!!!!!! It compiles and run!
    }

    In my mind, when I declared "D1<B, 10> od5", I allocated memory for 10
    elements of the type "B" -- as I did when I defined for the int type
    "D1<int, 5> od4". BUT, in the "int" case, I had to insert data in the
    vector "vt" of the template in order to properly access it. Therefore,
    how could I access the members of "od5" if I did not insert any class
    "B" object in the respective array "vt"?

    Wouldn't a more suited way for this case be:

    D1<B, 10> od5;

    for(int i = 0; i<10; i++)
    od5.push(new B); //Inserting class B objects.
    for(int i = 0; i<10; i++)
    od5.vt.dummy(); //Accessing members of the objects inserted.

    How about it??

    I appreciate any comment, suggestion, etc.

    Thank You!

    Marcelo
     
    Marcelo De Brito, May 26, 2009
    #1
    1. Advertising

  2. * Marcelo De Brito:
    >
    > I have created a template in which there is a generic vector/array


    It's not a "generic vector/array", it is a fixed size raw array.


    > that can hold any type defined by the programmer or built-in types.


    Well, this is subtle, but it can't hold just any type. If the type in question
    requires construction but does not support default construction, then there's no
    way to instantiate the array. std::vector solves this by using, well, advanced
    techniques, but std::vector still doesn't support non-copyable element type.


    > When I define the vector/array using built-in types (int, double,
    > etc.), I must insert data of the respective type in it.


    OK, taken as description of your class' interface.


    > But when I
    > define the array using a programmer defined type (e.g., a class), I
    > can access the class' members even though I did not insert any object
    > in it!


    That's your choice as designer of the class.

    It's a bad choice.

    Don't expose implementation details.


    > See the lines of code below for a better explanation.
    >
    > class B { //Programmer defined type.
    > public:
    > B() {};


    This leaves the 'id' member with indeterminate value => later UB.


    > B(int idd) : id(idd) {};


    OK.


    > B(const B&) {};


    This leaves the 'id' member with indeterminate value => later UB.


    > virtual ~B() {};
    > void setid(int idd) {id = idd;}
    > void dummy() {cout << "B::dummy()" << " " << "id = " << id <<
    > endl;}
    > private:
    > int id;
    > };
    >
    > template <class T, int size = 10>
    > class D1 {
    > public:
    > D1() : index(0) {};


    OK.


    > D1(const D1&) {};


    This leaves the 'index' member with indeterminate value => later UB.

    Depending on the type T it also leaves the 'vt' member with indeterminate values
    (which is OK), or default constructed values (which impacts negatively on
    efficiency).


    > virtual ~D1() {};


    OK.


    > T vt[size];


    This is a raw array of constant size.


    > void push(T* i) {
    > vt[index] = *i;
    > index++;
    > }


    This is bad design. It requires client code to use the address operator, and it
    opens the door for nullpointer argument, cuasing UB (most likely a crash). Make
    the formal argument type 'T const&'.



    > void exvet() {
    > for(int i = 0; i<index; i++)
    > cout << "vt[" << i << "] = " << vt << endl;
    > }


    OK, debugging?


    > void vetsize() {cout << size << endl;}


    OK, more debugging?


    > private:
    > int index;
    >
    > };
    >
    > int main()
    > {
    > D1<int, 5> od4; //First with int.
    >
    > for(int i = 0; i<5; i++)
    > od4.push(&i); //<- Inserting ints in the array. Fine.
    >
    > od4.exvet(); //<- Shows the ints int the array, Fine too.
    >
    > D1<B, 10> od5; //Now with the programmer defined type.
    >
    > for(int i = 0; i<10; i++)
    > od5.vt.dummy(); //<- !!!!!!!HERE!!!!!! It compiles and run!


    So?


    > }
    >
    > In my mind, when I declared "D1<B, 10> od5", I allocated memory for 10
    > elements of the type "B" -- as I did when I defined for the int type
    > "D1<int, 5> od4". BUT, in the "int" case, I had to insert data in the
    > vector "vt" of the template in order to properly access it.


    No, you didn't.


    > Therefore,
    > how could I access the members of "od5" if I did not insert any class
    > "B" object in the respective array "vt"?


    You can access the elements because you haven't prevented access.

    That's your choice as class designer.

    Make the array 'private' (or 'protected') to prevent client code access.



    > Wouldn't a more suited way for this case be:
    >
    > D1<B, 10> od5;
    >
    > for(int i = 0; i<10; i++)
    > od5.push(new B); //Inserting class B objects.
    > for(int i = 0; i<10; i++)
    > od5.vt.dummy(); //Accessing members of the objects inserted.
    >
    > How about it??


    Well, how about it?

    Have you tried actually writing that (and compiling and running)?


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
     
    Alf P. Steinbach, May 27, 2009
    #2
    1. Advertising

  3. Hi, Alf!

    Thank you very much for your comments and explanations!

    Concerning all the UB stuffs you aforementioned, it was just my
    lazyness of not taking them out when copying and pasting the code
    here. :)

    By the way, I appreciate your comments. Very useful, indeed.

    What I have not understood so far is the possibility of accessing
    class' members through an array that was just allocated, but has no
    objects inserted in it.

    However, I think the line "D1<B, 10> od5" automatically does all the
    allocation and object creation work. It will allocate 10 positions in
    the array "vt" and will declare/define them as the type "B", since
    that is the way it is defined in the template, and, as the default
    constructor "B()" needs no arguments, it is possible to the array "vt"
    to be created holding 10 class "B" objects. The line inside the
    template:

    T vt[size];

    Does all the necessary work and it is not needed to insert any objects
    in it, since they have already been inserted/created. I think.

    Have I got it right?

    Thank You!

    Marcelo
     
    Marcelo De Brito, May 27, 2009
    #3
  4. * Marcelo De Brito:
    > Hi, Alf!
    >
    > Thank you very much for your comments and explanations!
    >
    > Concerning all the UB stuffs you aforementioned, it was just my
    > lazyness of not taking them out when copying and pasting the code
    > here. :)
    >
    > By the way, I appreciate your comments. Very useful, indeed.
    >
    > What I have not understood so far is the possibility of accessing
    > class' members through an array that was just allocated, but has no
    > objects inserted in it.
    >
    > However, I think the line "D1<B, 10> od5" automatically does all the
    > allocation and object creation work. It will allocate 10 positions in
    > the array "vt" and will declare/define them as the type "B", since
    > that is the way it is defined in the template, and, as the default
    > constructor "B()" needs no arguments, it is possible to the array "vt"
    > to be created holding 10 class "B" objects. The line inside the
    > template:
    >
    > T vt[size];
    >
    > Does all the necessary work and it is not needed to insert any objects
    > in it, since they have already been inserted/created. I think.
    >
    > Have I got it right?


    Yep.


    Cheers & hth.,

    - Alf

    --
    Due to hosting requirements I need visits to <url: http://alfps.izfree.com/>.
    No ads, and there is some C++ stuff! :) Just going there is good. Linking
    to it is even better! Thanks in advance!
     
    Alf P. Steinbach, May 27, 2009
    #4
  5. Marcelo De Brito wrote:

    > Hi, Alf!
    >
    > Thank you very much for your comments and explanations!
    >
    > Concerning all the UB stuffs you aforementioned, it was just my
    > lazyness of not taking them out when copying and pasting the code
    > here. :)
    >
    > By the way, I appreciate your comments. Very useful, indeed.
    >
    > What I have not understood so far is the possibility of accessing
    > class' members through an array that was just allocated, but has no
    > objects inserted in it.
    >
    > However, I think the line "D1<B, 10> od5" automatically does all the
    > allocation and object creation work. It will allocate 10 positions in
    > the array "vt" and will declare/define them as the type "B", since
    > that is the way it is defined in the template, and, as the default
    > constructor "B()" needs no arguments, it is possible to the array "vt"
    > to be created holding 10 class "B" objects. The line inside the
    > template:
    >
    > T vt[size];
    >
    > Does all the necessary work and it is not needed to insert any objects
    > in it, since they have already been inserted/created. I think.
    >
    > Have I got it right?


    Yes.
    And to see that the array always initially contains default-constructed
    objects, try commenting out the B::B() constructor. Then the code will
    no longer compile.

    >
    > Thank You!
    >
    > Marcelo


    Bart v Ingen Schenau
    --
    a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
    c.l.c FAQ: http://c-faq.com/
    c.l.c++ FAQ: http://www.parashift.com/c -faq-lite/
     
    Bart van Ingen Schenau, May 27, 2009
    #5
  6. Marcelo De Brito

    James Kanze Guest

    On May 27, 12:52 am, Marcelo De Brito <> wrote:

    > I have created a template in which there is a generic
    > vector/array that can hold any type defined by the programmer
    > or built-in types. When I define the vector/array using
    > built-in types (int, double, etc.), I must insert data of the
    > respective type in it. But when I define the array using a
    > programmer defined type (e.g., a class), I can access the
    > class' members even though I did not insert any object in it!
    > See the lines of code below for a better explanation.


    > class B { //Programmer defined type.
    > public:
    > B() {};
    > B(int idd) : id(idd) {};
    > B(const B&) {};
    > virtual ~B() {};
    > void setid(int idd) {id = idd;}
    > void dummy() {cout << "B::dummy()" << " " << "id = " << id <<
    > endl;}
    > private:
    > int id;
    > };


    > template <class T, int size = 10>
    > class D1 {
    > public:
    > D1() : index(0) {};
    > D1(const D1&) {};
    > virtual ~D1() {};
    > T vt[size];
    > void push(T* i) {
    > vt[index] = *i;
    > index++;
    > }
    > void exvet() {
    > for(int i = 0; i<index; i++)
    > cout << "vt[" << i << "] = " << vt << endl;
    > }
    > void vetsize() {cout << size << endl;}
    > private:
    > int index;
    > };


    > int main()
    > {
    > D1<int, 5> od4; //First with int.


    > for(int i = 0; i<5; i++)
    > od4.push(&i); //<- Inserting ints in the array. Fine.


    > od4.exvet(); //<- Shows the ints int the array, Fine too.


    > D1<B, 10> od5; //Now with the programmer defined type.


    > for(int i = 0; i<10; i++)
    > od5.vt.dummy(); //<- !!!!!!!HERE!!!!!! It compiles and run!


    Why shouldn't it? You've created an array of 10 B in od5.vt.

    > }


    > In my mind, when I declared "D1<B, 10> od5", I allocated
    > memory for 10 elements of the type "B" -- as I did when I
    > defined for the int type "D1<int, 5> od4".


    In both cases, you've created an array of N elements. In the
    case of int, the elements are not initialized (since int has a
    trivial constructor), and reading the values before writing them
    would be undefined behavior (in practice, you'll normally just
    get a random value). In the case of B, the object has a user
    defined constructor, and that will be used to initialize them.
    (Given that the user defined constructor doesn't initialize B::id,
    accessing B::id before setting it will still result in undefined
    behavior.)

    > BUT, in the "int" case, I had to insert data in the vector
    > "vt" of the template in order to properly access it.


    No. No more so than in the case of B.

    > Therefore, how could I access the members of "od5" if I did
    > not insert any class "B" object in the respective array "vt"?


    The same way you could have accessed od4[ 3 ] before inserting
    any data.

    > Wouldn't a more suited way for this case be:


    > D1<B, 10> od5;


    > for(int i = 0; i<10; i++)
    > od5.push(new B); //Inserting class B objects.


    Why the new? (For that matter, why does push take a pointer?)

    > for(int i = 0; i<10; i++)
    > od5.vt.dummy(); //Accessing members of the objects inserted.


    When you define an array, all of the elements are created. If
    the array is of a non-POD class type, then its constructors are
    called; otherwise, it has an indeterminate value; reading this
    value is undefined behavior (unless the object has character
    type).

    It's possible to separate allocation from initialization, but it
    requires a bit more work. The array itself must be declared as
    unsigned char, and steps must be taken to ensure that it is
    properly aligned. And placement new must be used for
    initialization.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, May 27, 2009
    #6
  7. Hi, James!

    >Why the new? (For that matter, why does push take a pointer?)


    It was just some implementation details for the code work a little
    more without needing to debug it. It is just a code test and not the
    final product. :)

    Without the "(new B)" the code didn't compile.

    By the way, thank you very much for your explanations! :)

    Thank You!

    Marcelo
     
    Marcelo De Brito, May 27, 2009
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Theis
    Replies:
    2
    Views:
    486
    Chris Theis
    Jul 24, 2003
  2. tom_usenet
    Replies:
    0
    Views:
    549
    tom_usenet
    Jul 24, 2003
  3. Replies:
    1
    Views:
    2,129
    Gianni Mariani
    Jun 8, 2007
  4. Peng Yu
    Replies:
    3
    Views:
    791
    Thomas J. Gritzan
    Oct 26, 2008
  5. Philipp
    Replies:
    21
    Views:
    1,157
    Philipp
    Jan 20, 2009
Loading...

Share This Page