Topic: const ctor/dtor


Author: chu@prosun.first.gmd.de (Vladimir Chukharev)
Date: 1995/04/03
Raw View
In article <3lkg6c$enq@druid.borland.com>, pete@borland.com (Pete Becker) writes:
]In article <6572@bigfoot.first.gmd.de>, chu@prosun.first.gmd.de (Vladimir ]Chukharev) says:
]>
]
]>|>      const String s(data);
]>                       ^^^^
]>Oops!  'char*' passed as 'const char*'
]
] Not "Oops". It is perfectly legal, and one of the fundamentals
]of the type system. And it's precisely the reason that this attempt at
]formulating the meaning of const constructors fails.
] -- Pete

OK, I was too short.
The extention was proposed not by me.
It has been discussed, I can only summarize what I understand from
posts of Kevlin A P Henney (kevlin@wslint.demon.co.uk), Robin Rowe       (cpp@netcom.com), Martin Prange( prange@slbwa7.bln.sel.alcatel.de)
wikman@king.trs.ntc.nokia.com.
I'm not sure the list is full, my appologies...

So, you are right, not "Oops" currently. It should apear with
the proposed feature.

The main aim of the suggested extention is to ease abolishing
of C-style arrays wherever possible with no runtime penalty
in memory or speed. It's impotant for table programming technique,
for example.

The following is a legal C++ (with no extention proposed). It
compiles by g++ 2.6.3 (SunOS 4.1.3 on sparc). Cfront based
ObjectWorks CC.3.0.1 complains on const_cast and specialization
of ctor. Being fooled on those points, compiles OK.

===================t.cc=====================================
template<class T> class CNST{
  T* pp;
  unsigned len;
public:
  CNST(): pp(0), len(0) {}
  CNST(const T* p, unsigned ln);
  CNST(const T* p);              //to be specialized for T=char
  T* operator[](unsigned i) {return &pp[i];}             //for brevity
  const T* operator[](unsigned i) const {return &pp[i];} //for brevity
  ~CNST(){ delete[] pp; }
//  const CNST(const T* p, unsigned ln); // could be  : pp(p), len(ln) {}
//  const CNST(const T* p);        //to be specialized for T=char
//  ~CNST() const {}
};

template<class T> CNST<T>::CNST(const T* p, unsigned ln){
  len=ln;
  T* p1 = pp = new T[ln];
  const T* p2 = p;
  for (int i=ln; ln&&(*p1++ = *p2++); i--);
}

CNST<char>::CNST(const char* p){ // specialization
  len=strlen(p);
  pp=new char[len];
  strcpy(pp, p);
}

/*
const CNST<class T>::CNST(const T* p, unsigned ln){ // specialization
  pp=p;            // to be interpreted as   const CNT<char>* pp = p;
  len=ln;          // to be interpreted as   const int len = ln;
}

const CNST<char>::CNST(const char* p){ // specialization
  pp=p;            // to be interpreted as   const CNT<char>* pp = p;
  len=strlen(p);   // to be interpreted as   const int len = ln;
}
*/

int main(){
  int x[]={0, 1, 2, 3};
  const int y[]={0, 1, 2, 3};
          CNST<char>  s1("cs1");
          CNST<char>  s2((const char*)("cs2"));
          CNST<int>   i3(x, sizeof(x)/sizeof(x[0]));
          CNST<int>   i4(y, sizeof(y)/sizeof(y[0]));
    const CNST<char> cs5("cs5");                      // to be warned
    const CNST<char> cs6((const char*)("cs6"));
    const CNST<int>  ci7(x, sizeof(x)/sizeof(x[0]));  // to be error
    const CNST<int>  ci8(y, sizeof(y)/sizeof(y[0]));
    const CNST<char> cs9(const_cast<const char*>("cs9")); //CC error
//  const CNST<int>  ci10({1, 2, 3});
//  const CNST<int>  ci11(int y[]={1, 2, 3}, sizeof(y)/sizeof(y[0]));
//  const CNST<int>  ci12={int y[]={1, 2, 3}, sizeof(y)/sizeof(y[0])};
  *s1[1] = 'a';
//  *cs6[1] = 'a'; // is error always
  return 0;
}
==================================================================

All the stuff dealing with proposed feature is commented out.
(But not all comments are in there! Specificaly, in main() lines
declaring ci10, ci11 and ci12 will be discussed later.)

The proposed feature is to extend overloading of constructors
and destructors. For destructors overloading based on const/non-const
attribute of default parameter is asked, just as for all other member
functions. For constructors overloading on return type is wanted,
though only basing on constantness.

3 commented out lines in class declaration:
first line contains inline code after "//" which should be
interpreted same way as indicated in definition later (exept inlining).
Dtor is trivial for dynamic memory was not used by const.

Interpretation of pp=p; as const CNT<char>* pp = p; in body
of const ctor produces those "Oops" I wrote in my previous
posting.

Presented interpretation of suggested extention gives following in
main() (line is denoted by name declared in it):
s1, s2, i3, i4 work as usual.

cs5 is to produce warning for "cs5" is of char* type, not of const char*
(due to compatibility with C. Not all compilers do it).
cs9 is to be used insted, or cs6 (depricated).
ci7 should force error, closing a hole where const ci7 could be
changed through x variable.

cs5, cs6, ci8, cs9 do not duplicate data and do not waste time on
operator new invocation.


Now the dark side.

For destructor the asked feature lies in ideal model of const object,
wich "upon the entry into destructor becomes writable again" [D&E p.286],
i.e. at point of destructor invocation it is constant still. Overloaded
dtor can be easy faked (if ctor is overloaded) by means of a flag
in object, set by ctor accordingly.

Faking const ctor is not easy. One can try dynamic_cast. It
will work for polimorfic classes, but for int and char,
used here dynamic_cast will fail.

Overloading based on return type is forbidden now, though
was discussed. There is another close point: relaxed
overriding rules for virtual functions rely on return type
(base/derived relation for pointers and referenses).

Most nasty to my taste is the need to declare const C-ctyle array (y)
to use it in C++-style array declaration. Well, one can get rid
of y in scope using namespaces. And this makes it too wordy
for everyday use. ci10 initiation would be very desirable.
ci11 or ci12 are closer to existing code.
ci11 needs to allow declarations in actual param list. This has
some nice generalized views, but leads to great difficalties -
is ci11 a function declaration with omitted type?


I would vote for this proposed (again, I just summarized)
feature only if a good way to denote constant arrays of complicated
types in initializers is presented.

Thanks a lot, if you bear reading this till here.

--
Vladimir Chukharev
chu@first.gmd.de





Author: pete@borland.com (Pete Becker)
Date: 1995/04/04
Raw View
In article <6591@bigfoot.first.gmd.de>, chu@prosun.first.gmd.de (Vladimir Chukharev) says:
>
>In article <3lkg6c$enq@druid.borland.com>, pete@borland.com (Pete Becker) writes:
>]In article <6572@bigfoot.first.gmd.de>, chu@prosun.first.gmd.de (Vladimir ]Chukharev) says:
>]>
>]
>]>|>      const String s(data);
>]>                       ^^^^
>]>Oops!  'char*' passed as 'const char*'
>]
>]       Not "Oops". It is perfectly legal, and one of the fundamentals
>]of the type system. And it's precisely the reason that this attempt at
>]formulating the meaning of const constructors fails.
>]       -- Pete
>
>Yesterday I sent a long answer. I  forget to indicate in it
>that declaring ctor as const has some implication on
>parameters types. Now, trying to explicitly formulate it,
>I recognized that this implication is realy too big.
>
>Declaring a formal parameter as const A* is promising that
>actual parameter will not be changed. For const ctor to be
>safe this should be modified to demanding that actual parameter
>is const A*. May be I'm not the only who oversighted this...
>

Yes: A* is convertible to const A*, without requiring that the A
actually become const. That's deep in the type system, and it's
where this proposal runs into trouble.

>Pete Becker, thank you for your patience and sorry in took
>your time.

No problem. It's an interesting discussion, and I learned several
things from it.
 -- Pete





Author: chu@prosun.first.gmd.de (Vladimir Chukharev)
Date: 1995/04/04
Raw View
In article <3lkg6c$enq@druid.borland.com>, pete@borland.com (Pete Becker) writes:
]In article <6572@bigfoot.first.gmd.de>, chu@prosun.first.gmd.de (Vladimir ]Chukharev) says:
]>
]
]>|>      const String s(data);
]>                       ^^^^
]>Oops!  'char*' passed as 'const char*'
]
] Not "Oops". It is perfectly legal, and one of the fundamentals
]of the type system. And it's precisely the reason that this attempt at
]formulating the meaning of const constructors fails.
] -- Pete

Yesterday I sent a long answer. I  forget to indicate in it
that declaring ctor as const has some implication on
parameters types. Now, trying to explicitly formulate it,
I recognized that this implication is realy too big.

Declaring a formal parameter as const A* is promising that
actual parameter will not be changed. For const ctor to be
safe this should be modified to demanding that actual parameter
is const A*. May be I'm not the only who oversighted this...

Pete Becker, thank you for your patience and sorry in took
your time.

--
Vladimir Chukharev
chu@first.gmd.de