BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

A philosophical question about inconsistence between buitin

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++)
View previous topic :: View next topic  
Author Message
Vladimir Grigoriev
Guest





PostPosted: Tue May 08, 2007 5:08 pm    Post subject: A philosophical question about inconsistence between buitin Reply with quote



A philosophical question about inconsistence between built-in types and
user-defined types. :)

Assume that I am writing a container as a simple array.

const int DefaultSize = 10;

template < typename T >
class Array
{
public:
Array( int size = DefaultSize );
Array( const Array &rhs );
~Array(){ delete [] pType; }
// Other methods...
private:
T *pType;
int itsSize;
};

And I have a class that mimics integers


class TInt
{
public:
TInt(): intValue( 0 ){}
TInt( int theValue ): intValue( theValue ){}
TInt & operator=( const TInt &rhs )
{
intValue = rhs.intValue;
return *this;
}
friend std::ostream & operator<<( std::ostream & out, const TInt &
rhs )
{
out << rhs.intValue;
return out;
}
// Other methods and operators...
private:
int intValue;
};

The constructor of the Array is

template < typename T >
Array<T>::Array( int size ): itsSize( size )
{
pType = new T[size];
}

Thus if I will declare in main()

Array< TInt > UserIntArray;

I will get an *initialized* array each element of which will have 0 as a
value. For each TInt element of the Array the TInt constructor will be
called only once.

Assume that now I am declaring Array of int;

Array< int > BuiltinIntArray;

I will get *uninitialized* array. Very bad!. Smile So to have an initialized
array of built-in types I should to change the Array constructor.

template < typename T >
Array<T>::Array( int size ): itsSize( size )
{
pType = new T[size];
for ( int i = 0; i < size; i++ ) pType[i] = 0; // additional statement
}

In this case after declaring

Array< int > BuiltinIntArray;

I will get an initialized array at last.
But what about user-defined type?
For user-defined type (TInt) instead of calling its constructor only once
for each element of the array I will get that 1) the default constructor
will be called for each element; 2) the constructor with parameter will be
called to change 0 to class TInt for each element; 3) the assignment
operator will be called to assign a temporar TInt object to each element of
the array. Very bad! Smile :)

Vladimir Grigoriev
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Tue May 08, 2007 5:47 pm    Post subject: Re: A philosophical question about inconsistence between bui Reply with quote



"Vladimir Grigoriev" <vlad.moscow (AT) mail (DOT) ru> writes:

Quote:
template < typename T
Array<T>::Array( int size ): itsSize( size )
{
pType = new T[size];
for ( int i = 0; i < size; i++ ) pType[i] = 0; // additional statement
}

In this case after declaring

Array< int > BuiltinIntArray;

I will get an initialized array at last.
But what about user-defined type?

In your code above, the user defined type would be first default
constructed, and then have 0 assigned to it. This may or may not
compile, depending on what operations type T supports.

Quote:
For user-defined type (TInt) instead of calling its constructor only once
for each element of the array I will get that 1) the default constructor
will be called for each element; 2) the constructor with parameter will be
called to change 0 to class TInt for each element; 3) the assignment
operator will be called to assign a temporar TInt object to each element of
the array. Very bad! Smile Smile

The way this is can be handled more uniformly is to allocate an array
of properly aligned bytes, and then iteratively use placement new to
instantiate each element in that array. If any object constructor
throws, you must destroy all the previously constructed elements
before exiting your Array constructor.

In your Array destructor you'd have to explicitly invoke the
destructor on each element, and then delete[] the array of bytes.

--
Chris (TeamB);
Back to top
Vladimir Grigoriev
Guest





PostPosted: Tue May 08, 2007 6:26 pm    Post subject: Re: A philosophical question about inconsistence between bui Reply with quote



"Chris Uzdavinis (TeamB)" <chris (AT) uzdavinis (DOT) com> wrote in message
news:864pmnv5x0.fsf (AT) explicit (DOT) atdesk.com...
Quote:

In your code above, the user defined type would be first default
constructed, and then have 0 assigned to it. This may or may not
compile, depending on what operations type T supports.

Well, and what to do if T does not support assignment operator? How to join
initialization of built-in types and user-defined types in one container?

Quote:
The way this is can be handled more uniformly is to allocate an array
of properly aligned bytes, and then iteratively use placement new to
instantiate each element in that array. If any object constructor
throws, you must destroy all the previously constructed elements
before exiting your Array constructor.

It makes things more complicated!

Vladimir Grigoriev.
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Tue May 08, 2007 6:41 pm    Post subject: Re: A philosophical question about inconsistence between bui Reply with quote

"Vladimir Grigoriev" <vlad.moscow (AT) mail (DOT) ru> writes:

Quote:
"Chris Uzdavinis (TeamB)" <chris (AT) uzdavinis (DOT) com> wrote in message
news:864pmnv5x0.fsf (AT) explicit (DOT) atdesk.com...

In your code above, the user defined type would be first default
constructed, and then have 0 assigned to it. This may or may not
compile, depending on what operations type T supports.

Well, and what to do if T does not support assignment operator? How
to join initialization of built-in types and user-defined types in
one container?

You either must document your requirements (requiring users to adhere
to them), or you don't do the assignment and drop that requirement entirely.

NOTE: default 'construction' of an integer will initialize it to zero.

int x1 = int(); // x1 is guaranteed to be 0
int * x2 = new int(); // x2 is guaranteed to point to an (int) 0.

However:

int x1; // uninitialized
int * x2 = new int; // points to uninitialized data

Quote:
It makes things more complicated!

That depends. You are simply being explicit in the construction and
destructon of the elements you're managing, but you handle ALL of them
in a consisten manner, and do NOT need to do any post-construction
assignment.

The only alternate I can think of (maintaining your original approach)
is to specialize your Array based on some type-traits of T. If T is a
built-in type, then you allocate the array and then memset the data to
0. If it's not a built-in type, you allocate the array and rely on
the default constructors to be run for you.

This approach seems complicated in its own regard, for different
reasons: you have to determine if T is built-in (using boost or tr1
type_traits library can help), and then you need to specialize
templates for different cases. The cases are individually easier, but
it's more code and they're handled differently.

With my suggestion, you have one implementation that works for
everything. Like always, there is always a trade-off.

--
Chris (TeamB);
Back to top
Sergiy Kanilo
Guest





PostPosted: Wed May 09, 2007 2:52 am    Post subject: Re: A philosophical question about inconsistence between bui Reply with quote

"Vladimir Grigoriev" <vlad.moscow (AT) mail (DOT) ru> wrote in message
news:46406795 (AT) newsgroups (DOT) borland.com...
Quote:
A philosophical question about inconsistence between built-in types and
user-defined types. Smile

[...]
Quote:
class TInt
{
public:
TInt(): intValue( 0 ){}
TInt( int theValue ): intValue( theValue ){}
TInt & operator=( const TInt &rhs )
{
intValue = rhs.intValue;
return *this;
}
[...]
private:
int intValue;
};
[...]
array of built-in types I should to change the Array constructor.

template < typename T
Array<T>::Array( int size ): itsSize( size )
{
pType = new T[size];
for ( int i = 0; i < size; i++ ) pType[i] = 0; // additional statement
}

For user-defined type (TInt) instead of calling its constructor only once
for each element of the array I will get that 1) the default constructor
will be called for each element; 2) the constructor with parameter will be
called to change 0 to class TInt for each element; 3) the assignment
operator will be called to assign a temporar TInt object to each element
of the array. Very bad! Smile Smile

Which is exactly how you ask TInt to behave.
If you don't want initialization by TInt constructor (so it more resemple
int),
it should be

TInt::TInt(){}

If you do not want creating temporary when assigning to an object
(even if good compiler will optimize extra copying) then provide
proper assignment operator

TInt& TInt::operator=( int rhs )
{
intValue = rhs;
return *this;
}

Cheers,
Serge

PS: copuple workarounds

1) new int[10]() should initialize array with zeros
(unfortunately it is in theory only; AFAIK BCB or BDS do not
support this feature)

2) std::vector has exactly the functionality you want for
your Array constructor (for TInt as is originally written),
without extra assignments and temporary objects
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.