Topic: Some ideas about C++ and a question


Author: A.Main@dcs.warwick.ac.uk (Zefram)
Date: 1996/03/07
Raw View
Valentin Bonnard  <bonnardv@pratique.fr> wrote:
>1) String literals
>~~~~~~~~~~~~~~~~~~
>String literals should be const char* instead of char* (if it is not
>already the case).

Actually they're char[], which in practice is almost always decayed to
char*.  The reason they aren't char const[] is that a lot of existing C
code does things like `char *foo="bar";', because const didn't exist in
K&R C.

In my opinion, C++ code tends to use const correctly much more than C
code does.  (I personally always write const correctness into my C
code, but a lot of people do not, quite apart from the matter of
existing code.)  It would therefore probably not be disastrous to have
string literals have type char const[] in C++, though it would be in
C.  Maybe in the next round of standardisation?

>2) Placement operators
>~~~~~~~~~~~~~~~~~~~~~~
>class Object {
>        void    operator+ // or / or whatever
>                         (Object& result, const Object& b) const;
>        void    operator* (Object& result) const;
>        Object  operator* (const Object& result) const; // old one
>}
>
>should be called respectively by:
>a = b + c;
[...]

GCC has a better syntax for this, using a declaration "return result"
between the parameter list and the function body.  The function has a
return value in the usual way, but if it doesn't contain a return
statement with a value then the object in the return declaration is
returned.

>4) Conversion of Type** to const Type**
>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>It's ok, this is an error; but why cannot Type** be converted to const Type*
>const* ?

It can in C++, but not in C.  It is in fact safe, but the discovery of
the problem with converting T** to T const** led to the present C rule,
which was cast in stone (figuratively) before the C++ rule was
developed.

-zefram
--
Andrew Main <zefram@dcs.warwick.ac.uk>


[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: bonnardv@pratique.fr (Valentin Bonnard)
Date: 1996/03/12
Raw View
[Note: I have tried to post normally this followup, but it seam it
didn't work; this follows news:4hdctd$r1p@engnews1.Eng.Sun.COM (Steve
Clamage's article) Please remove this note before posting. ]

clamage@Eng.Sun.COM (Steve Clamage) wrote:
>Valentin Bonnard <bonnardv@pratique.fr> writes:
>
>>I have 4 ideas about C++ and a question.
>
>>1) String literals
>>~~~~~~~~~~~~~~~~~~
>>String literals should be const char* instead of char* (if it is not
>>already the case).
>
>Yes, it is clearly the "right" thing to do, but it is not the case
>for the same reason it is not the case in Standard C: it would break
>too much existing code to make the change.

Perhaps, but in C void* converted to anything* and it's not the case in C++: this broke more C code (I think, or a least more of my old C code) then what I propose.

Or could it be a compiler option (that all compilers should have) to make string literals char* ?


>>2) Placement operators
>>~~~~~~~~~~~~~~~~~~~~~~
>>class Object {
>>        void    operator+ // or / or whatever
>>                         (Object& result, const Object& b) const;
binary (compute *this + b, put the result in 'result')
>>        void    operator* (Object& result) const;     #2
unary (compute *(*this), put the result in 'result')
>>        Object  operator* (const Object& result) const; // old one
                                           ^^^^^^ ops! should be named b
binary (compute *this + b, return the result)
>>}
>
>>should be called respectively by:
>>a = b + c;
>
>>and a = *b;
>
>>and (old one) a*b;
>
>>This will solve the [well-known] problem of copying the result into a temporary.
>>The compatibility will be preserved since old syntax will be allowed to.
>
>You will have to present this idea in more detail. I can't figure out
>what you are proposing. It looks like you want the function marked #2
>to be some form of unary dereferencing operator, but that would change
>its existing meaning of a member binary (multiplication) operator.

The story begin with a class Object for the construction and destruction is not trivial (and take some time):

Object  a, b, c;
a = b @ c;

where @ is one of: + - * / % & | ^ && || etc... (but not one of: += -= *= /= %= &= |= ^=)

I want to be able to write (using the friend notation to make it a little more clear):
void    operator @ (Object& result, const Object& a, const Object& b);

instead of
Object    operator @ (const Object& a, const Object& b);

The definition would become (for example):

void    operator @ (Object& result, const Object& a, const Object& b)
{
    result = a;
    result @= b; // direct operation
}

rather than
Object    operator @ (const Object& a, const Object& b)
{
    Object result = a;
    result @= b;

    return Object;      // temporary created with copy constructor, Object deleted,
}                       // then temporary copied into a, and temporary deleted

The old style should still be allowed, and the operator signature is clearly distinct from the one I propose.

For unary operators, the idea is exactly the same, but it's a bit more difficult to see if it's a binary operator or a unary operator because my syntax and an argument:
(where @ is one of ! ~ unary * etc...)

Object  operator @ (const Object&); // again friend version instead of member version
become
void    operator @ (Object&, const Object&); // unary [2]

The problem with * is that the [2] is difficult to distinguish from
Object  operator * (const Object&, const Object&); // binary *, return the result

But my operator return void, so it could be used as an indication: I don't think many people currently have code with
void operator * (Object&, const Object&); // I think this is currently legal
and who write a * b; where a will be modified !

This king of strange code would break if my proposal was accepted for unary operators, but I really don't think it is very serious.

>>3) Use of explicit keyword
>>~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>>void    foo (explicit Derived* object) ...
>
>Evidently you want this to mean that "*object" is of type "Derived"
>and not of any type derived from "Derived". I guess I don't see
>the utility of the declaration. You can create a type which cannot be
>derived from, if that is what you want. If you don't want that, I
>don't see why the author of "foo" wants to be sure no derived type
>is ever passed to it. What programming problem is being solved here?
>
>The whole idea of public derivation is that a derived type can be
>used where ever a base type is expected. Why does the author of foo
>want to ensure that the actual object has, for example, no additional
>data, functionality, or instrumentation, when the author of Derived
>has no objections to the possibility?
>
>If for some reason you do care about the actual type of *object,
>wouldn't it be enough to use an RTTI expression in the function?

This could help for functions that take a Base[]:

class Base {
    public:
        void    (*func) ();
};

class Derived {
    public:
        long    dummy;
};

void    foo_safe (explicit Base[]);
void    foo_bad (Base[]);

void    test ()
{
    Base*     der = new Derived[10];

    foo_bad (der); // pass at compile time, then crash
    foo_safe (der);
// the compiler will tell you 'cannot convert from Base* to explicit Base*'
}

void    foo_bad (Base[] b)
{
    for (int i=0; i<10; i++)
        (b[i].func) (); // function call here to be sure that it crash ;->
}

void    foo_safe (explicit Base[] b) // do the same thing
{
    for (int i=0; i<10; i++)
        (b[i].func) ();
}

I know a could use a container, but the notion of array use sometimes useful for class too.

Well, this was not the point of my idea: I wanted to the compiler to know at compile time the 'real' type of the object, not:
- use RTTI (contrary of compile time !)
- not just to protect from error (see example above)
- 'create a type which cannot be derived from', as Steve Clamage say.
  (The class Derived can be derived from, since, it has a normal declaration.)

I wrote:
> object.VirtualFunc (); // nop (compiler does not generate code for this)

Since VirtualFunc is virtual, the compiler must generate code for it, even when object is a Base& and Base::VirtualFunc is defined as { } *except* if:
(a) the variable is passed by value
(b) you use explicit

(a) as obvious disadvantages in terms of speed for big classes, so the last solution is (b)...

Note: the rule for the qualifier are the *inverse* of the rules for cv (const/volatile):
~~~~~
T* -> const T*          const T* !=> T*
T* -> volatile T*       volatile T* !=> T*
but
explicit T* -> T*       T* !=> explicit T*

where -> means can be converted to and !=> means CAN'T be converted to.


>>4) Conversion of Type** to const Type**
>>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>>It's ok, this is an error; but why cannot Type** be converted to const Type*
>>const* ?
>
>For the same reason: it could cause a violation of constness without
>a cast. The draft standard does allow Type** to be converted to
>"Type*const*", since that cannot cause any such violation.

I don't see how you could violate constness _without_ the cast; if you know, please tell me.


Valentin Bonnard
bonnardv@pratique.fr
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de>
Date: 1996/03/13
Raw View
In article <v01530500ad6a43009478@[194.98.4.120]> bonnardv@pratique.fr
(Valentin Bonnard) writes:
|> clamage@Eng.Sun.COM (Steve Clamage) wrote:
|> >Valentin Bonnard <bonnardv@pratique.fr> writes:

|> >>4) Conversion of Type** to const Type**
|> >>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|> >
|> >>It's ok, this is an error; but why cannot Type** be converted to
|> >>const Type* const* ?

It can.  It was banned in the C standard, and the C++ committee only
changed this rule recently, so it is possible that many compilers
don't implement it yet.  (It was banned by mistake in the C standard;
the wording to forbid Type** -> Type const** was made too tight.)

|> >For the same reason: it could cause a violation of constness without
|> >a cast. The draft standard does allow Type** to be converted to
|> >"Type*const*", since that cannot cause any such violation.

|> I don't see how you could violate constness _without_ the cast; if you
|> know, please tell me.

I think Steve just misread your statement.  (I know I did the first
time through.)  Why you cannot convert Type** to Type const** is
almost a FAQ, and since since that was the title of point 4...

--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
                -- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]