Re: C++ Conversion functions for pointers

From: Paul (paulmmm01_at_hotmail.com)
Date: 05/03/04

  • Next message: Mark : "Re: Global variables!"
    Date: 2 May 2004 17:10:46 -0700
    
    

    "B. v Ingen Schenau" <bart@ingen.ddns.info> wrote in message news:<c73bq3$haua1$1@ID-135549.news.uni-berlin.de>...
    > Paul wrote:
    >
    > > What exactly are you saying is causing UB here?
    > > I thought you were meaning the subscript operator function but now I'm
    > > not so sure what your talking about.
    >
    > In the code originally posted, you had a statement (paraphraded)
    > Variant *itsArray = new ObjA[size];
    > and later you accessed that array through itsArray. That is where the UB
    > comes into play in the code posted here.

    Ah ok.

    >
    > If you start to use an array of pointers, then the UB I referred to is no
    > longer present.
    Ok that's actually what I intended to do but I had just got to that
    bit and that was the bit I was stuck with.
    I was concerned by how I was going to create a new int then assign it
    to variable. I hadn't at that point realised how easy it was to simply
    create a Variant(int). I hadn't gotten around to properly constructing
    the Array at that point.
    >
    > <snip>
    > >
    > > Well just to make it clear..
    > >
    > > I know I can create an array of Variant pointers and assign to these
    > > pointers either Variants or classes derived from variants.
    > >
    > > And whether these pointers are in array or not
    > > i.e:
    > > Variant* = new Variant(int);
    > > Variant* = new ClassDerivedfromVariant;
    > >
    > > As you can see for built in types I need to create a Variant type ,
    > > converted to the built in type. So If I were allocating dependant on
    > > an argument I would first need to check to see if the argument was a
    > > Variant(or Derived from Variant) before allocating.
    > >
    > > This is a bit messy and I would like to do this in one statement.
    >
    > Unfortunately, C++ simply does not allow that kind of type conversion.
    >
    > What you could do, is create a design like this:
    >
    > class VariantArray
    > {
    > std::vector<Variant*> array;
    > VariantArray(const VariantArray&); /* not allowed, for simplicity */
    > VariantArray& operator=(const VariantArray&); /* not allowed, for
    > simplicity */
    > public:
    > /* Create an array with N pre-allocated, *empty* slots */
    > VariantArray(int N = 0) : array(N) {}
    > ~VariantArray()
    > {
    > for (size_t i=0; i < array.size(); i++)
    > delete array[i];
    > }
    >
    > /* Add something to the array */
    > template <class T>
    > void push_back(const T& elem)
    > {
    > array.push_back(new T(elem));
    > }
    > void push_back(int elem)
    > {
    > array.push_back(new Variant(elem));
    > }
    > void push_back(float elem)
    > {
    > array.push_back(new Variant(elem));
    > }
    >
    > /* access operators */
    > const Variant& operator[](size_t index) const
    > {
    > return *array[index];
    > }
    > Variant& operator[](size_t index)
    > {
    > return *array[index];
    > }
    >
    > /* more members */
    > };
    >
    > I have deliberately choisen not to make the entire class a template, because
    > it should hold a mixture of types.
    > The method used to be able to store both typed derived from Variant and
    > types that can be stored directly in a Variant object with overloading of
    > the member(s) that add elements to the array.
    >
    Ah this is quite good but there is a problem with using vector. If you
    examine the address of the reference the subscript operator returns it
    is always 000000. This means that virtual assignment operator
    wouldn't work for UDT's as they require this value to be cast to gain
    access to their non virtual member functions.
    I don't know how this is, the vector seems to screw it up somehow.
    But the design is good apart from that.If this can be remedied it
    would maybe be better to use vector.
    > <snip>
    > > I don't want this I wan't to get a Variant*, so I am asking if there
    > > is a way to change the default behaviour, perhaps by operator overload
    > > or by using conversion functions or both.
    >
    > As all pointers are built-in types, you can not alter the way one is
    > converted to another, or if such a conversion is permitted.
    > The closest you can probably get is to create a smart-pointer class, but
    > that is still no silver bullet.
    >
    > >
    > > I realise this part of my code had problems and perhaps I should have
    > > defined more clearly what I was trying to do. The reason being I am
    > > unsure about how best to construct the data in the Array. I don't yet
    > > know if an array of Variant* 's is the best solution.
    > > Perhaps I could store the data in arrays of different types and then
    > > have some kind of logic inbetween that encapsulates indexing of all
    > > the arrays into one.
    > >
    > > SO I am keeping an open mind about how best to store the different
    > > types of Variants until I have explored a few different possibilities.
    > > It's more a design issue than anything.
    > >
    > > I have 3 or more options in my mind at the moment and I'm not sure
    > > which would be best.
    > >
    > > 1) Create an array of variant pointers and test for variant classes
    > > before allocation.
    >
    > That is very hard to do entirely by hand, but when enlisting the help of the
    > compiler, it can be turned into a copy/paste excercise.
    > The compiler can be of assistance if you use overloading (as I did in my
    > example) or template specialisation.

    What I had in mind was incorporating into Variant class a C-string
    property named itsType. I can simply check this property to see it the
    type is correct.
    Of course this means another prerequisite for UDT's (they must assign
    their type name to this property) :(

    template specialization is an idea I need to look into further. This
    sounds like a *very* good idea. I could speacialise each built in
    type. The only thing that worries me is that I am planning in the
    future to template Variant class and also have class specializations
    so I can make elements be of types such as string, vector, DirectXObj
    or whatever , I need to take some time to examine this more carefully.
    Also I need a new compiler because my current does not support partial
    specialisation, every time I get into any complex template arrangement
    I end up hitting a brick wall because of this.:(
     
    >
    > > 2) Create an array of variant pointers and look into overloading new.
    >
    > That will not be a viable approach. The operator new() that you can overload
    > only handles the memory-allocation part. Constructing an actual object in
    > that memory can not be altered, unless you alter the compiler you are
    > using.

    Yes I have looked into this a little bit and it doesn't look like the
    answer.
    >
    > > 3) create an array of variant pointers for UDT's and and array of
    > > variants(non pointer) for built in types, then create some kind of
    > > indexing map to make the two arrays behave like one.
    >
    > That will be possible, but it will probably give you some bookkeeping
    > headaches.
    Yes I don't fancy this one myself.
    >
    > <snip>
    > >
    > > AHA & TIA.
    > > Paul.
    >
    > Bart v Ingen Schenau

    Here is a little program I have it working, still a bit fragile but it
    works, and with some of your design incorporated :

    #include <iostream>

    class Variant{
    public:
            Variant():itsDataInt(0),itsType("Variant"){}
            Variant(int arg):itsDataInt(arg),itsType("Variant(int)"){}
            virtual ~Variant(){}
            virtual Variant& operator=(const Variant& rhs){return *this;}
            const char* getType() const {return itsType;}
    private:
            int itsDataInt;
    protected:
            const char* itsType;
    };

    class Class1: public Variant{
    public:
            Class1():itsData(0){itsType="Class1";}
            Class1(int arg):itsData(arg){itsType="Class1";}
            Class1(const Class1& rhs){
                    itsData = rhs.itsData;
                    itsType="Class1";
            }
            Class1& operator=(const Variant& rhs){
                    if(rhs.getType()== "Class1"){
                            const Class1* temp = static_cast<const Class1*>(&rhs);
                            itsData = temp->itsData;
                            return *this;
                    }else
                            std::cerr << "Class1 Error:operator= does not convert "<<
    rhs.getType()<<'\n';
            }
            Class1& operator=(const Class1& rhs){
                    itsData = rhs.itsData;
                    return *this;
            }
            ~Class1(){}
    private:
            int itsData;
    };

    class vArray{
    public:
            vArray():itsSize(0){
                    itsArray = 0;
            }
            vArray(size_t size):itsSize(size){
                    itsArray = new Variant*[size];
                    for(size_t i=0;i<size;i++)
                            itsArray[i] = 0;
            }
            ~vArray(){
                    for(int i=0; i<itsSize; i++)
                            delete itsArray[i];
                    delete [] itsArray;
            }
            
            Variant& operator[](size_t index){
                    return *(itsArray[index]);
            }
            
            const Variant& operator[](size_t index) const{
                    return *(itsArray[index]);
            }

            template <class T>
                    void push(int index, const T& arg){
                            if(index<itsSize){
                                    /*check type first ? maybe*/
                                    delete itsArray[index];
                                    itsArray[index] = new T(arg);
                            }
                    }

            void push(int index, int elem){
                    if(index<itsSize){
                            /*check type first ? maybe*/
                            delete itsArray[index];
                            itsArray[index]= new Variant(elem);
                    }
            }
                                    
    private:
            Variant** itsArray;
            int itsSize;
    };

    int main(){
            Class1 c1(4);
            int x(5);
            vArray va1(2);
            va1.push(0, c1);
            va1.push(1, x);
            c1 = va1[0];
            return 0;
    }

    As you can see by the UDT operator= overload I need to cast the
    pointer , this is where the vector messes up.

    Also I have just realised that I won't be using methods for simple
    assignments as the subscript operator will handle this, but for
    converting an element type I will use metohds. But at least this
    example demonstrates that it works.

    Once again thanks for your help.
    Paul.


  • Next message: Mark : "Re: Global variables!"

    Relevant Pages

    • Re: C++ Conversion functions for pointers
      ... I know I can create an array of Variant pointers and assign to these ... >> But the problem I am having is converting an int pointer to a Variant ...
      (alt.comp.lang.learn.c-cpp)
    • Re: C++ Conversion functions for pointers
      ... If you start to use an array of pointers, then the UB I referred to is no ... > I know I can create an array of Variant pointers and assign to these ... C++ simply does not allow that kind of type conversion. ...
      (alt.comp.lang.learn.c-cpp)
    • Re: ReDim not working as expected. Array expert needed.
      ... MsgBox TypeName) ' Type Variant() ... examples of how array dimensions work in VBA. ... Sub ArrayStudies14() ... Dim MyArray As Variant ' Declare nonarray variant. ...
      (microsoft.public.excel.programming)
    • Re: Differance between Array and Pointers
      ... Well, except that arrays tend to be much larger than pointers, and the ... An array is a contiguous region of memory containing N elements of M ... indexing vs. a loop). ...
      (comp.arch.embedded)
    • [RFCv2][PATCH] flexible array implementation
      ... I call it a flexible array. ... storage for pointers to the second level. ... all locking must be provided by the caller. ... make sure to pass in &ptr instead of ptr. ...
      (Linux-Kernel)