By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
464,557 Members | 1,023 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 464,557 IT Pros & Developers. It's quick & easy.

Anything wrong with this function?

P: n/a
Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

Someone else said it was fine - was she right?
Feb 2 '07 #1
Share this Question
Share on Google+
83 Replies

P: n/a
Anonymous wrote:
Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

Someone else said it was fine - was she right?
It depends on what kind of 'fine' you are asking about...

Formally the code is indeed perfectly fine.

One possible nitpick is that currently 'errToText' is a non-static
member function of class 'MyClass'. Since it doesn't need to access any
members of the class (at least in this form), maybe it should be turned
into a _static_ member function. Maybe not. Hard to say with such little
context.

--
Best regards,
Andrey Tarasevich

Feb 2 '07 #2

P: n/a
Anonymous wrote:
>
char const* MyClass::errToText(int err) const
Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const

{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

--
Maksim A Polyanin
Feb 2 '07 #3

P: n/a
Andrey Tarasevich wrote:
Anonymous wrote:
>Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

Someone else said it was fine - was she right?

It depends on what kind of 'fine' you are asking about...

Formally the code is indeed perfectly fine.

One possible nitpick is that currently 'errToText' is a non-static
member function of class 'MyClass'. Since it doesn't need to access any
members of the class (at least in this form), maybe it should be turned
into a _static_ member function. Maybe not. Hard to say with such little
context.
Another style issue here is that magic numbers are used. I'd make something
like:

enum Error
{
NoError, NotEnough, TooMuch
};

and then use that instead of int and magic numbers for the errors.

Feb 2 '07 #4

P: n/a
"Grizlyk" <gr******@yandex.ruwrote in message news:ep*********@aioe.org...
Anonymous wrote:
>>
char const* MyClass::errToText(int err) const

Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const
The parameter is local for the function, nobody's going to care whether that
int is const or not. In fact, the standard doesn't care either. These two
function declarations declare the same function:

void foo(int);
void foo(const int);

- Sylvester
Feb 2 '07 #5

P: n/a
On Feb 2, 2:07 pm, Anonymous <inetl...@hotmail.comwrote:
Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}

}

Someone else said it was fine - was she right?
I have a doubt:

Aren't the above character strings "No error", "Not enough", ... local
to the member function MyClass::errToText(...)? If they are local,
then won't the returned pointers be dangling upon an exit from this
function?

Feb 2 '07 #6

P: n/a
On 2 Feb, 15:27, "frame" <v.sri...@gmail.comwrote:
On Feb 2, 2:07 pm, Anonymous <inetl...@hotmail.comwrote:
Came across some code summarized as follows:
char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}
Someone else said it was fine - was she right?

I have a doubt:

Aren't the above character strings "No error", "Not enough", ... local
to the member function MyClass::errToText(...)? If they are local,
then won't the returned pointers be dangling upon an exit from this
function?
No. String literals are allocated statically. The returned pointer
will be valid throughout the lifetime of the program.

Gavin Deane

Feb 2 '07 #7

P: n/a
In article <ep*************@news.t-online.com>,
Rolf Magnus <ra******@t-online.dewrote:
Andrey Tarasevich wrote:
Anonymous wrote:
Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

Someone else said it was fine - was she right?
It depends on what kind of 'fine' you are asking about...

Formally the code is indeed perfectly fine.

One possible nitpick is that currently 'errToText' is a non-static
member function of class 'MyClass'. Since it doesn't need to access any
members of the class (at least in this form), maybe it should be turned
into a _static_ member function. Maybe not. Hard to say with such little
context.

Another style issue here is that magic numbers are used. I'd make something
like:

enum Error
{
NoError, NotEnough, TooMuch
};

and then use that instead of int and magic numbers for the errors.
I was unused to the return of string literals, but eventually
found a reference to this style in C. I had always written
similar code (in C) in table style - something like this:

#define numberof(arr) ((unsigned) (sizeof(arr) / sizeof(arr[0])))

enum MCErrorCode
{
MC_ERROR_NONE = 0,
MC_ERROR_2FEW = 1,
MC_ERROR_2MUCH = 2,
MC_ERROR_UNKNOWN = -1
};

const char* MyClass::errToText(int err) const
{
static struct MCError
{
MCErrorCode errcode;
char* errmsg;
} mcErrors [] =
{
{ MC_ERROR_NONE, "No error" },
{ MC_ERROR_2FEW, "Not enough" },
{ MC_ERROR_2MUCH, "Too much" },
{ MC_ERROR_UNKNOWN, "Unknown error" }
};

const int nerrs = numberof(mcErrors);

int i;
for (i = 0; i < nerrs-1; i++)
{
if (err == mcErrors[i].errcode)
break;
}

return mcErrors[i].errmsg;
}
Feb 2 '07 #8

P: n/a

"Anonymous" <in******@hotmail.comwrote in message
news:in****************************@news-server.houston.rr.com...
In article <ep*************@news.t-online.com>,
Rolf Magnus <ra******@t-online.dewrote:

#define numberof(arr) ((unsigned) (sizeof(arr) / sizeof(arr[0])))
template<class T, size_t Nsize_t numberof(T (&)[N])
{
return N;
}

Difference: it only works for actual arrays (compile error otherwise) and it
complies to regular name lookup rules ;)

- Sylvester
Feb 2 '07 #9

P: n/a
Sylvester Hesp wrote:
"Anonymous" <in******@hotmail.comwrote in message
news:in****************************@news-server.houston.rr.com...
>In article <ep*************@news.t-online.com>,
Rolf Magnus <ra******@t-online.dewrote:

#define numberof(arr) ((unsigned) (sizeof(arr) / sizeof(arr[0])))

template<class T, size_t Nsize_t numberof(T (&)[N])
{
return N;
}

Difference: it only works for actual arrays (compile error otherwise) and it
complies to regular name lookup rules ;)
And it's not a compile-time constant.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
Feb 2 '07 #10

P: n/a
frame wrote:
On Feb 2, 2:07 pm, Anonymous <inetl...@hotmail.comwrote:
>Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}

}

Someone else said it was fine - was she right?

I have a doubt:

Aren't the above character strings "No error", "Not enough", ... local
to the member function MyClass::errToText(...)?
No. They have static storage duration.

Feb 2 '07 #11

P: n/a
Sylvester Hesp wrote:
>Anonymous wrote:
>>>
char const* MyClass::errToText(int err) const

Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const

The parameter is local for the function, nobody's going to care whether
that int is const or not. In fact, the standard doesn't care either.
It is bad only for standard, because it is really different function for
user. Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying for
some functions.
These two function declarations declare the same function:

void foo(int);
void foo(const int);
--
Maksim A Polyanin
Feb 2 '07 #12

P: n/a
Grizlyk wrote:
Sylvester Hesp wrote:
>>Anonymous wrote:

char const* MyClass::errToText(int err) const

Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const

The parameter is local for the function, nobody's going to care whether
that int is const or not. In fact, the standard doesn't care either.

It is bad only for standard, because it is really different function for
user.
Not this one, this is only different for the implementor of the function:
the user passes by value and keeps the original anyway. In fact, the client
code has no way to observe from the outside, whether the parameter is
modified by the function internally.
Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying for
some functions.
Not this one. This one would just tie down the hands of implementors of the
function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of the
result by modifying i internally. Tough luck. That is why the standard is
well-advised to say:
>These two function declarations declare the same function:

void foo(int);
void foo(const int);
Note that the situation is completely different for parameters passed by
reference.
Best

Kai-Uwe Bux
Feb 2 '07 #13

P: n/a
Gavin Deane wrote:
On 2 Feb, 15:27, "frame" <v.sri...@gmail.comwrote:
On Feb 2, 2:07 pm, Anonymous <inetl...@hotmail.comwrote:
Came across some code summarized as follows:
char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}
Someone else said it was fine - was she right?
I have a doubt:

Aren't the above character strings "No error", "Not enough", ...
local to the member function MyClass::errToText(...)? If they are
local, then won't the returned pointers be dangling upon an exit
from this function?

No. String literals are allocated statically. The returned pointer
will be valid throughout the lifetime of the program.
Right. Now, the somewhat similar looking case:

char* f()
{
char arr[] = "Some text";

return arr;
}
Would indeed be returning a pointer to invalid memory.

Brian
Feb 2 '07 #14

P: n/a
Kai-Uwe Bux wrote:
...
>Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying for
some functions.

Not this one. This one would just tie down the hands of implementors of the
function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of the
result by modifying i internally. Tough luck. That is why the standard is
well-advised to say:
>>These two function declarations declare the same function:

void foo(int);
void foo(const int);
...
Well, every decision is a trade off. I can see the benefit of distinguishing
between these two functions. Consider the following example

void foo(const int, const int);
void bar(const int, const int);

...
foo(a, b);
bar(a, b);

In this case the compiler has to generate code that passes the same set of
arguments to all three functions. On a typical compiler with stack-based
argument passing it would look as follows (just a sketch)

push a
push b
call foo
pop b, a

push a
push b
call bar
pop b, a

Functions 'foo' and 'bar' will use the values in the stack as their local
variables. If the parameters are declared as 'const', it means that these
functions are not allowed to modify them. If the compiler could know that from
outside of those functions, it could produce a much more compact and efficient code

push a
push b
call foo
call bar
pop b, a

Unfortunately with the current language specification this is not possible in
general case.

--
Best regards,
Andrey Tarasevich
Feb 2 '07 #15

P: n/a
Kai-Uwe Bux wrote:
>
Grizlyk wrote:
>Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying
for
some functions.

Not this one. This one would just tie down the hands of implementors of
the
function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of the
result by modifying i internally. Tough luck. That is why the standard is
well-advised to say:

Note that the situation is completely different for parameters passed by
reference.
Yes, const reference explicitly requires from compiler to share data, but
violating const modifier in "void foo(const int)" for most cases is just
error sign, because function declatation is interface and it is not good to
change interface of anything "on fly".

A man, who developed function interface said with the help of cost modifier,
that value must not change for implementation, because it is external
constant (as M_PI for example) and M_PI can not be equal to 6 or 7 for any
purpose, it is nonsence.

In our example we must not expect from "err" in "...::errToText(int err)"
changes, because err is original error code, we must not change it during
work. If we need. we can do it explicit like this:

int &err_memory_as_ordinary_data_storage=const_cast<in t&>(err);

and work with "err_memory_as_ordinary_data_storage" in free manner.

I agree, that parameter "passed by value" can create separated copy of its
data, but I think for parameter "passed by const value" must not be duty to
create new copy of data, and in theory const data can be shared by compiler
as compiler can eliminate unnecessary call of copy ctor on return.

At least in my program I give to compiler chance to optimizing the const
value if it can. And i am even refusing to use ctor as ordinary function
call, because i think variables must be treated by compiler as variables and
compiler must _not_ expect from ctor any hidden activity, in addition to
creating variable.

And I think compiler must have keyword for explicit protect variables from
any optimizations, something like "volatile".

--
Maksim A Polyanin
Feb 2 '07 #16

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>>
Grizlyk wrote:
>>Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying
for
some functions.

Not this one. This one would just tie down the hands of implementors of
the
function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of
the result by modifying i internally. Tough luck. That is why the
standard is well-advised to say:

Note that the situation is completely different for parameters passed by
reference.

Yes, const reference explicitly requires from compiler to share data, but
violating const modifier in "void foo(const int)" for most cases is just
error sign, because function declatation is interface and it is not good
to change interface of anything "on fly".

A man, who developed function interface said with the help of cost
modifier, that value must not change for implementation, because it is
external constant (as M_PI for example) and M_PI can not be equal to 6 or
7 for any purpose, it is nonsence.

In our example we must not expect from "err" in "...::errToText(int err)"
changes, because err is original error code, we must not change it during
work.
No, it is not the original error code object that you must not change. It is
a local copy that you can change at will. Those are the rules of the
language.
If we need. we can do it explicit like this:

int &err_memory_as_ordinary_data_storage=const_cast<in t&>(err);

and work with "err_memory_as_ordinary_data_storage" in free manner.
Huh? I don't follow. const_casting away constness for actual const objects
is undefined behavior. So if err is actually const, this code is dubious.

I agree, that parameter "passed by value" can create separated copy of its
data,
"can"? Unless the compiler proves that it can optimize away the copy, the
copy is guaranteed to be made.
but I think for parameter "passed by const value" must not be duty
to create new copy of data, and in theory const data can be shared by
compiler as compiler can eliminate unnecessary call of copy ctor on
return.
At least in my program I give to compiler chance to optimizing the const
value if it can.
A sufficiently smart compiler can do that already; although, I concede that
const can provide useful hints to the compiler in this regard.

And i am even refusing to use ctor as ordinary function
call, because i think variables must be treated by compiler as variables
and compiler must _not_ expect from ctor any hidden activity, in addition
to creating variable.

And I think compiler must have keyword for explicit protect variables from
any optimizations, something like "volatile".
Both issues seems to be unrelated to the const issue.
Best

Kai-Uwe Bux
Feb 2 '07 #17

P: n/a
Kai-Uwe Bux wrotte:
>>
Grizlyk wrote:
>In our example we must not expect from "err" in "...::errToText(int err)"
changes, because err is original error code, we must not change it during
work.

No, it is not the original error code object that you must not change. It
is
a local copy that you can change at will. Those are the rules of the
language.
I think, declaring copy of any data (variable passed by value) as const, a
man, who have developed function interface, said that even this concrete
copy of the data _logically_ can not be changed, in spite of all other
copyes of the same object (look - any copy of M_PI can not be equal to 6).

Word _logically_ means that compiler must protect your internal function
implementation from logically wrong writing into the variable, even if the
writing do not disturb all other copyes of the variable, because the
variable has been passed by value.
>If we need. we can do it explicit like this:

int &err_memory_as_ordinary_data_storage=const_cast<in t&>(err);

and work with "err_memory_as_ordinary_data_storage" in free manner.

Huh? I don't follow. const_casting away constness for actual const objects
is undefined behavior. So if err is actually const, this code is dubious.
I think, in some cases (for inline function for exmple) compiler can
undersand are you trying to write to const_casted object here or not. If
not, compiler can skip useless copy ctor, if yes, compiler can create copy,
making variable accessable to write.
>
>I agree, that parameter "passed by value" can create separated copy of
its
data,

"can"? Unless the compiler proves that it can optimize away the copy, the
copy is guaranteed to be made.
Yes, it is a question - to do always copy of variable passed by value or not
to do. It is possible, that there are known to C++ experts reasons of
concrete behaviour or there are random selected conventions assumed by
standard.

But i think the next: in theory, if we have a following code
--
struct X
{
int sign;
X():sign(0){}
X(cons X&):sign(1){}
};

void foo(const X);
X x;
void test(){ foo(x); }
--
in general case programmer must not expect, that inside "foo(x)" he will get
"copy of ::x" (x.sign==1), not the same as "::x" (x.sign==0), but he must
expect, that original "::x" will not see, that "foo(x)" has been called and
exited.

I can prove my opinion by reasons of parameter or variable declaration,
because "foo(const X)" request accesst to X, but do not request
"X::ctor(X&)" calling, so we must not expect and assuming hidden activity
from ctors.

Declaration "foo(const X)" requests own copy of X, but does require nothing
about relationships between the copy of X and other copyes of X.

In other side, declaration "foo(const X&)" garantees, that copy ctor never
will be called, so "foo(const X)" is not strictly opposite to "foo(const
X)". We could explicit write copy ctor like this:

void test(){ foo( X(x) ); }

but by accordance with reasons of variable usage and creating compiler can
have ability to eliminate "X(x)" and pass to "foo" global "::x" reference in
fact, to reduce size and speed.

It looks like we have no reasons to make extra copy of data, but here can be
special cases (when we must do it), so I think in order to force compiler to
make copy of data always in any concrete place, we must have any C++ keyword
for it, something like "volatile" keyword.

In spite of theory, there are many well-known limitations, when behaviour is
well defined, for example for functions with "extern C" linkage "foo(const
X)" will always make a stack copy of global "::x", but the stack copy can be
shared by series of "foo(const X)" calls, nothing to deny it, maybe
excluding standard.

--
Maksim A Polyanin
Feb 3 '07 #18

P: n/a
Andrey Tarasevich wrote:
Kai-Uwe Bux wrote:
>...
>>Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying
for some functions.

Not this one. This one would just tie down the hands of implementors of
the function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of
the result by modifying i internally. Tough luck. That is why the
standard is well-advised to say:
>>>These two function declarations declare the same function:

void foo(int);
void foo(const int);
...

Well, every decision is a trade off. I can see the benefit of
distinguishing between these two functions. Consider the following example

void foo(const int, const int);
void bar(const int, const int);

...
foo(a, b);
bar(a, b);

In this case the compiler has to generate code that passes the same set of
arguments to all three functions. On a typical compiler with stack-based
argument passing it would look as follows (just a sketch)

push a
push b
call foo
pop b, a

push a
push b
call bar
pop b, a

Functions 'foo' and 'bar' will use the values in the stack as their local
variables. If the parameters are declared as 'const', it means that these
functions are not allowed to modify them. If the compiler could know that
from outside of those functions, it could produce a much more compact and
efficient code

push a
push b
call foo
call bar
pop b, a

Unfortunately with the current language specification this is not possible
in general case.
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged. I
am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
Best

Kai-Uwe Bux
Feb 3 '07 #19

P: n/a
On 2 Feb, 20:32, "Grizlyk" <grizl...@yandex.ruwrote:
Yes, const reference explicitly requires from compiler to share data, but
violating const modifier in "void foo(const int)" for most cases is just
error sign, because function declatation is interface and it is not good to
change interface of anything "on fly".
That argument is flawed. The things that you should not change "on the
fly" are the things that can affect existing client code. The const-
ness of an argument taken by value is not one of those things so in
this context is not part of the function's interface at all.
In our example we must not expect from "err" in "...::errToText(int err)"
changes, because err is original error code, we must not change it during
work. If we need. we can do it explicit like this:

int &err_memory_as_ordinary_data_storage=const_cast<in t&>(err);

and work with "err_memory_as_ordinary_data_storage" in free manner.
If err is declared const, that will not work.
If err is not declared const, that will work, but is equivalent to and
far more cumbersome than
....::errToText(int& err)
But that doesn't help if what you want is to be able to modify the
value without affecting the original object. That is most easily
achieved by
....::errToText(int err)

Gavin Deane

Feb 3 '07 #20

P: n/a
Kai-Uwe Bux wrote:
...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged. I
am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
...
Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

--
Best regards,
Andrey Tarasevich

Feb 3 '07 #21

P: n/a
Andrey Tarasevich wrote:
Kai-Uwe Bux wrote:
>...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged.
I am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
...

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.
True, but isn't that more or less the same data flow analysis through which
the compiler has to go anyway to issue errors for const violations? After
all, a const_cast<just has the compiler shut up about something that
otherwise would require a diagnostic message. If so, I don't see a reason
for not using the information obtained in this analysis for optimization.
Best

Kai-Uwe Bux
Feb 3 '07 #22

P: n/a
Kai-Uwe Bux wrote:
>Kai-Uwe Bux wrote:
>>...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged.
I am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
...

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

True, but isn't that more or less the same data flow analysis through which
the compiler has to go anyway to issue errors for const violations? After
all, a const_cast<just has the compiler shut up about something that
otherwise would require a diagnostic message. If so, I don't see a reason
for not using the information obtained in this analysis for optimization.
...
I don't see how it could be the same. Errors for const violations are
always based on immediate compile-time context limited to a single
expression. There's no serious "data flow" involved.

But in order to determine whether a 'const-reference' parameter can be
replaced with a 'value' parameter the compiler has to analyze the entire
function in order to find out if there are any modification attempts
there. It is safe to say that an exhaustive analysis is simply
impossible in general case, since it can easily depend on run-time context.

--
Best regards,
Andrey Tarasevich

Feb 3 '07 #23

P: n/a
Kai-Uwe Bux wrote:
>
Andrey Tarasevich wrote:
>>
Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

True, but isn't that more or less the same data flow analysis through
which
the compiler has to go anyway to issue errors for const violations? After
all, a const_cast<just has the compiler shut up about something that
otherwise would require a diagnostic message. If so, I don't see a reason
for not using the information obtained in this analysis for optimization.

When you are use const_cast<you must be shure, that variable after cast is
allowed to write (not placed in ROM or readonly segment), and compiler can
and I think must to control it. In other words, compiler can be "shut up-ed"
if only const modifier is provide logic protection, not hadware protection.

For most cases you no need to use memory of alredy unnecessary const
variable to store new data, it is enough other memory: registers and stack.

--
Maksim A Polyanin
Feb 3 '07 #24

P: n/a
Kai-Uwe Bux wrote:
...
There's also another detail that might prevent compiler from replacing '
"const-reference' parameter with a 'value' parameter. A reference that
is direct-bound has to preserve the address-identity of the object. For
example, in the following code

const int a;

void foo(const int& i) {
if (&i == a) {
...
}
}

foo(a);

the condition in the 'if' must be satisfied. This will not work
correctly if the compiler looses the attachment between the parameter
and the actual argument.

--
Best regards,
Andrey Tarasevich

Feb 3 '07 #25

P: n/a
Andrey Tarasevich wrote:
Kai-Uwe Bux wrote:
>>Kai-Uwe Bux wrote:
...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable
and then decide to put copies on the stack that surely will remain
unchanged. I am not sure whether current C++ compilers would do this
kind of optimization or whether they will blindly push addresses onto
the stack. ...

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

True, but isn't that more or less the same data flow analysis through
which the compiler has to go anyway to issue errors for const violations?
After all, a const_cast<just has the compiler shut up about something
that otherwise would require a diagnostic message. If so, I don't see a
reason for not using the information obtained in this analysis for
optimization. ...

I don't see how it could be the same. Errors for const violations are
always based on immediate compile-time context limited to a single
expression. There's no serious "data flow" involved.

But in order to determine whether a 'const-reference' parameter can be
replaced with a 'value' parameter the compiler has to analyze the entire
function in order to find out if there are any modification attempts
there.
Exactly. But I think, the compiler has to check the very same thing anyway.
Consider

void f ( int const & x ) {
...
x = 3;
...
}

I thaught, that supposed to raise an error. So, the compiler has to go
through the body an flag each possible modifications of x as a const
violation.

I think, if the body compiles cleanly, and there is no const_cast<>, the
compiler can push the value of x onto the stack instead of its address.
It is safe to say that an exhaustive analysis is simply
impossible in general case, since it can easily depend on run-time
context.
Huh?
Best

Kai-Uwe Bux
Feb 3 '07 #26

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>>
Andrey Tarasevich wrote:
>>>
Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

True, but isn't that more or less the same data flow analysis through
which
the compiler has to go anyway to issue errors for const violations? After
all, a const_cast<just has the compiler shut up about something that
otherwise would require a diagnostic message. If so, I don't see a reason
for not using the information obtained in this analysis for optimization.


When you are use const_cast<you must be shure, that variable after cast
is allowed to write (not placed in ROM or readonly segment), and compiler
can and I think must to control it. In other words, compiler can be "shut
up-ed" if only const modifier is provide logic protection, not hadware
protection.
The standard says otherwise. See [7.1.5.1/4]:

Except that any class member declared mutable (7.1.1) can be modified, any
attempt to modify a const object during its lifetime (3.8) results in
undefined behavior.

Since it is undefined behavior, no diagnostic is required.

Also, the standard does not say anything about ROM segments or hardware
protection.
[snip]
Best

Kai-Uwe Bux

Feb 3 '07 #27

P: n/a
In article <in****************************@news-server.houston.rr.com>,
in******@hotmail.com says...
Came across some code summarized as follows:

char const* MyClass::errToText(int err) const
{
switch (err)
{
case 0: return "No error";
case 1: return "Not enough";
case 2: return "Too much";
default: return "Unknown error";
}
}

Someone else said it was fine - was she right?
If you mean "is is all right for a function to return the address of a
string literal?", then the answer is yes. A string literal has static
storage duration.

Personally, I'd probably do something more like:

char const *MyClass::errToText(unsigned err) const {
char *names[]={
"No Error", "Not Enough", "Too Much", "Unknown Error"
};

return names[std::min(err, 3)];
}

But that may just indicate my distaste for switch statements.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Feb 3 '07 #28

P: n/a
Kai-Uwe Bux wrote:
>...
But in order to determine whether a 'const-reference' parameter can be
replaced with a 'value' parameter the compiler has to analyze the entire
function in order to find out if there are any modification attempts
there.

Exactly. But I think, the compiler has to check the very same thing anyway.
Consider

void f ( int const & x ) {
...
x = 3;
...
}

I thaught, that supposed to raise an error. So, the compiler has to go
through the body an flag each possible modifications of x as a const
violation.
Well, this alone already hints at the formally different "structure" of
these two issues. A simple const-violation is a purely _local_ issue:
it's just a report-and-forget type of thing. But for the purpose of
parameter replacement, this information has to be collected and turned
into a function-wide (i.e. more _global_) property attached to each
relevant parameter.

Yes, I understand that this alone is still very easy to do. But that is
not all.
I think, if the body compiles cleanly, and there is no const_cast<>, the
compiler can push the value of x onto the stack instead of its address.
Not enough. The compiler also has to watch for things like this

void f ( int const & x ) {
...
int const& y = x;
...
const_cast<int&>(y) = 3
...
}
>It is safe to say that an exhaustive analysis is simply
impossible in general case, since it can easily depend on run-time
context.

Huh?
...
It could be something like

void f ( int const & x ) {
...
int a = 0;
int const& y = rand() % 2 == 0 ? x : a;
...
const_cast<int&>(y) = 3
...
}

Of course, in this case the compiler can (or has to) follow the "better
safe the sorry" route and assume that 'y' can be bound to 'x'.

Finally, in addition ot the address problem mentioned in my neighboring
message, there's also the following issue. It is possible that the
parameters of the following function

void foo(const int& a, int& b)

will be direct-bound to the same referent at the time of call (that is
also run-time context, BTW)

int x = 0;
foo(x, x);

In that case inside the function the following relationships shall hold

1) &a == &b shall be true
2) if we do 'b = 5' then a == 5 shall be true

Once the reference parameters are replaced with values, these
requirements will become hard to satisfy, even with a very smart
compiler. Because they depend on the run-time context which is external
to the function itself.

--
Best regards,
Andrey Tarasevich

Feb 3 '07 #29

P: n/a
Andrey Tarasevich wrote:
Kai-Uwe Bux wrote:
>...

There's also another detail that might prevent compiler from replacing '
"const-reference' parameter with a 'value' parameter. A reference that
is direct-bound has to preserve the address-identity of the object. For
example, in the following code

const int a;

void foo(const int& i) {
if (&i == a) {
...
}
}

foo(a);

the condition in the 'if' must be satisfied. This will not work
correctly if the compiler looses the attachment between the parameter
and the actual argument.
I think, that still could be taken care of by an analysis of the function
body.
Unfortunately, there is yet another problem preventing compilers from doing
this optimization: namely that this operation affects the code used to do
the function call; i.e., before control is transfered to the function
parameters are pushed onto the stack and what is pushed is exactly at issue
with this optimization. But this might be a problem when you use function
pointers. E.g., suppose you have a function

void f ( const int & x );

for which the compiler wants to do this optimization. How should the
compiler treat code like

void (*g) ( const int & );
g = &f;
int i = 0;
g(i);

Now, the compiler simply cannot predict whether f is going to be used like
that without knowing the program as a whole. In particular, it might be
impossible to do this in the presence of separate compilation.
Oh well, too bad.
Best

Kai-Uwe Bux
Feb 3 '07 #30

P: n/a
Andrey Tarasevich wrote:
[about replacing const & parameters with values]
Finally, in addition ot the address problem mentioned in my neighboring
message, there's also the following issue. It is possible that the
parameters of the following function

void foo(const int& a, int& b)

will be direct-bound to the same referent at the time of call (that is
also run-time context, BTW)

int x = 0;
foo(x, x);

In that case inside the function the following relationships shall hold

1) &a == &b shall be true
2) if we do 'b = 5' then a == 5 shall be true
True, but if you do b = 5 the compiler has to refrain from optimizing const
& parameters to values anyway. So I don't think this introduces an
additional difficulty.
Once the reference parameters are replaced with values, these
requirements will become hard to satisfy, even with a very smart
compiler. Because they depend on the run-time context which is external
to the function itself.
I still think it wouldn't be too hard to make a static conservative analysis
of the function body. If the compiler cannot prove in a straight forward
way that the values remain unmodified and the addresses are not needed,
then the optimization is forbidden.
Best

Kai-Uwe Bux
Feb 3 '07 #31

P: n/a
Kai-Uwe Bux wrote:
Grizlyk wrote:
>Kai-Uwe Bux wrote:
>>>
After all, a const_cast<just has the compiler shut up about something
that otherwise would require a diagnostic message.

When you are use const_cast<you must be shure, that variable after cast
is allowed to write (not placed in ROM or readonly segment), and compiler
can and I think must to control it. In other words, compiler can be "shut
up-ed" if only const modifier is provide logic protection, not hadware
protection.

The standard says otherwise. See [7.1.5.1/4]:

Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results in
undefined behavior.

Since it is undefined behavior, no diagnostic is required.
I think the words "attempt to modify a const object during its lifetime"
means what if you are accessing to object violating constness, for example
with the help of reinterpret_cast<>. But in the case of const_cast<>
compiler "know" what you are doing and can trace you actions, so compiler
_must_ check - is the object placed in writable memory or not - if not or
not sure, it can make temporary or print error/warning.

We are speaking about parameter passed by value. I do not insist on using
const parameter as non-const with the help of const_cast<(the usage is
safe for example, for C-linkage functions).

But if you say, that compiler do not support safe const_cast<in general,
it is bad.
Also, the standard does not say anything about ROM segments or hardware
protection.
I think it is wrong standard behaviour, because most systems has readonly &
writable data segments, and it is good, if programmer will get control for
placement of data. Systems, that have no the segments, can silently ignore
the explicit declared segments because the segments just more limited than
ordinary memory.

My example with my_auto_ptr shows, that we can not avoid dangers of
unspecified memory usage even by creating simple memory wrapper, to avoid
the dangers we need exclude usage of new/new[] operators or extend template
syntax.

But evev if C++ will can do it in general avoiding new/new[] operators looks
like bad idea.

--
Maksim A Polyanin
Feb 4 '07 #32

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>Grizlyk wrote:
>>Kai-Uwe Bux wrote:

After all, a const_cast<just has the compiler shut up about something
that otherwise would require a diagnostic message.

When you are use const_cast<you must be shure, that variable after
cast is allowed to write (not placed in ROM or readonly segment), and
compiler can and I think must to control it. In other words, compiler
can be "shut up-ed" if only const modifier is provide logic protection,
not hadware protection.

The standard says otherwise. See [7.1.5.1/4]:

Except that any class member declared mutable (7.1.1) can be modified,
any attempt to modify a const object during its lifetime (3.8) results
in undefined behavior.

Since it is undefined behavior, no diagnostic is required.

I think the words "attempt to modify a const object during its lifetime"
means what if you are accessing to object violating constness, for example
with the help of reinterpret_cast<>. But in the case of const_cast<>
compiler "know" what you are doing and can trace you actions, so compiler
_must_ check - is the object placed in writable memory or not - if not or
not sure, it can make temporary or print error/warning.
You have it slightly backwards: the compiler will issue an error if a
reinterpret_cast<is used to cast away constness. From the standard:

[5.2.10/2] The reinterpret_cast operator shall not cast away constness...

On the other hand, const_cast<has the only purpose of telling the compiler
not to bitch when an object is modified that, within the local context, is
considered const (e.g., a parameter passed as const &). If the actual
object was declared const to begin with, you get undefined behavior.
We are speaking about parameter passed by value. I do not insist on using
const parameter as non-const with the help of const_cast<(the usage is
safe for example, for C-linkage functions).

But if you say, that compiler do not support safe const_cast<in general,
it is bad.
By and large, there is no such thing as a "safe cast" in C++. Whenever a
cast pops up, chances are you doing something whicked. That's why it is
good that C++ casts are grepable, so that you can audit the code.
>Also, the standard does not say anything about ROM segments or hardware
protection.

I think it is wrong standard behaviour, because most systems has readonly
& writable data segments, and it is good, if programmer will get control
for placement of data. Systems, that have no the segments, can silently
ignore the explicit declared segments because the segments just more
limited than ordinary memory.
I think the idea is that those provision vary from platform to platform and
that it is not a good idea for the standard to be prescriptive in this
area.

My example with my_auto_ptr shows, that we can not avoid dangers of
unspecified memory usage even by creating simple memory wrapper, to avoid
the dangers we need exclude usage of new/new[] operators or extend
template syntax.

But evev if C++ will can do it in general avoiding new/new[] operators
looks like bad idea.
Here, I don't understand what you mean.
Best

Kai-Uwe Bux
Feb 4 '07 #33

P: n/a
Kai-Uwe Bux wrote:
Grizlyk wrote:
>>
I think the words "attempt to modify a const object during its lifetime"
means what if you are accessing to object violating constness, for
example
with the help of reinterpret_cast<>. But in the case of const_cast<>
compiler "know" what you are doing and can trace you actions, so compiler
_must_ check - is the object placed in writable memory or not - if not or
not sure, it can make temporary or print error/warning.

You have it slightly backwards: the compiler will issue an error if a
reinterpret_cast<is used to cast away constness. From the standard:
>>for example with the help of reinterpret_cast<>.
I want to say, that you can get access to const data over pointer to
non-const data, and C++ will not try to protect you from the actions. You
can apply series of C-style casts, void*, reinterpret_cast<>s, unions etc to
make pointer.
>But if you say, that compiler do not support safe const_cast<in
general,
it is bad.

By and large, there is no such thing as a "safe cast" in C++. Whenever a
cast pops up, chances are you doing something whicked. That's why it is
good that C++ casts are grepable, so that you can audit the code.
We are not speaking about "safe cast", but writing to readonly memory and
other actions like this is wrong idea, especialy when C++ can easy test it.
>>Also, the standard does not say anything about ROM segments or hardware
protection.

I think it is wrong standard behaviour, because most systems has readonly
& writable data segments, and it is good, if programmer will get control
for placement of data. Systems, that have no the segments, can silently
ignore the explicit declared segments because the segments just more
limited than ordinary memory.

I think the idea is that those provision vary from platform to platform
and
that it is not a good idea for the standard to be prescriptive in this
area.
Describe at least one real or theoretical system, where decaring data as
readonly will be error.
>My example with my_auto_ptr shows, that we can not avoid dangers of
unspecified memory usage even by creating simple memory wrapper, to avoid
the dangers we need exclude usage of new/new[] operators or extend
template syntax.

But even if C++ will can do it in general avoiding new/new[] operators
looks like bad idea.

Here, I don't understand what you mean.
Search "// C-style danger here - we can pass not only new Tobj" string in
"auto_ptr" topic.

--
Maksim A Polyanin
Feb 4 '07 #34

P: n/a
Andrey Tarasevich wrote:
>
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.
Compiler at compile time can link any variable with some attributes, as
"accsessed", "written" and so on. Based on values of the attributes,
compiler can detect "unused variables", for example and can detect
const_cast<applyed to variable.

--
Maksim A Polyanin
Feb 4 '07 #35

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>Grizlyk wrote:
>>>
I think the words "attempt to modify a const object during its lifetime"
means what if you are accessing to object violating constness, for
example
with the help of reinterpret_cast<>. But in the case of const_cast<>
compiler "know" what you are doing and can trace you actions, so
compiler _must_ check - is the object placed in writable memory or not -
if not or not sure, it can make temporary or print error/warning.

You have it slightly backwards: the compiler will issue an error if a
reinterpret_cast<is used to cast away constness. From the standard:
>>>for example with the help of reinterpret_cast<>.
I want to say, that you can get access to const data over pointer to
non-const data, and C++ will not try to protect you from the actions. You
can apply series of C-style casts, void*, reinterpret_cast<>s, unions etc
to make pointer.
>>But if you say, that compiler do not support safe const_cast<in
general,
it is bad.

By and large, there is no such thing as a "safe cast" in C++. Whenever a
cast pops up, chances are you doing something whicked. That's why it is
good that C++ casts are grepable, so that you can audit the code.

We are not speaking about "safe cast", but writing to readonly memory and
other actions like this is wrong idea, especialy when C++ can easy test
it.
It can test this only at run time. The standard, however, does not require
the implementations to perform this test because it does not want to
mandate this overhead.
>
>>>Also, the standard does not say anything about ROM segments or hardware
protection.

I think it is wrong standard behaviour, because most systems has
readonly & writable data segments, and it is good, if programmer will
get control for placement of data. Systems, that have no the segments,
can silently ignore the explicit declared segments because the segments
just more limited than ordinary memory.

I think the idea is that those provision vary from platform to platform
and
that it is not a good idea for the standard to be prescriptive in this
area.

Describe at least one real or theoretical system, where decaring data as
readonly will be error.
I cannot relate this statement to the talk about ROM and hardware from
before. If you just want to indicate that the compiler is free to put a
piece of data into a read-only segment of memory, you can already use
const. I thaught, you had something in mind that would, say, specify an
explicit address range. Then, the compiler is not required to know whether
the data is read-only.

[snip]

Kai-Uwe Bux
Feb 4 '07 #36

P: n/a
Kai-Uwe Bux wrote:
>>>
Grizlyk wrote:

But if you say, that compiler do not support safe const_cast<in
general,
it is bad.

By and large, there is no such thing as a "safe cast" in C++. Whenever a
cast pops up, chances are you doing something whicked. That's why it is
good that C++ casts are grepable, so that you can audit the code.

Grizlyk wrote:
>We are not speaking about "safe cast", but writing to readonly memory and
other actions like this is wrong idea, especialy when C++ can easy test
it.

It can test this only at run time. The standard, however, does not require
the implementations to perform this test because it does not want to
mandate this overhead.
No, test can be done at compile time, because cast between
"T heap*" and "T readonly code*" must be disabled.
>
>Describe at least one real or theoretical system, where decaring data as
readonly will be error.

I cannot relate this statement to the talk about ROM and hardware from
before. If you just want to indicate that the compiler is free to put a
piece of data into a read-only segment of memory, you can already use
const.
-1-

Better to say, that compiler is ignoring existance such of special and
useful memory areas, as some kind of readonly/writeonly memory. The using
unqualified C-style pointers can lead to runtime errors, when pointers from
readonly segments will be mixed with ordinary memory.

I am repeating, that to avoid the possible errors:
1. we can refuse using C-style pointers without explicit memory qualifiers
and new/new[]
2. or new/new[] must return user defined classes instead of C-style pointers
3. or we must invent user-defined operators instead of new/new[] to create
dynamic data

-2-
Maybe explicit memory specifiers can be useful as itself (without concerning
dynamic data problems), they do not disturb systems allocating only one
segment, but allow to other systems manualy place data into concrete
segments, "switching on" hardware memory control.

Let you have (it is real sysytem)

- code1 code segment as can not rw
- code2 code segment as readonly
- data1 data segment as readonly
- data2 data segment as rw
- data3 data segment as writeonly (for your process)

where "Tobj" and "ptr" will be placed in following example?

const Tobj *const ptr;
const Tobj * ptr;
Tobj *const ptr;
Tobj * ptr;

but with explicit memory specification

default segments:

data1 - for const T
data2 - for T

// ! not C++

//Tobj -code2
//ptr -data2
code Tobj *ptr; //error code2 is const
code const Tobj *ptr;

//Tobj -data1
//ptr -data2
const Tobj *ptr;
const_cast<Tobj&>(ptr); //error - data1 readonly
//or compiler will remove Tobj into data2 and print warning
//or compiler will make temporary and print warning

//Tobj -data2
//ptr -data2
writable const Tobj *ptr; //software constness
const_cast<Tobj&>(ptr); //ok

//Tobj -data2
//ptr -data2
const Tobj dseg * ptr; //software constness for Tobj

//Tobj -data2
//ptr -data1
Tobj *const ptr;

//Tobj -data2
//ptr -data2
Tobj *const writable ptr; //software constness for ptr

//Tobj -data2
//ptr -code2
Tobj *code ptr; //error - code is readonly
Tobj *const code writeable ptr; //error - no writeable code seg
Tobj *const code ptr;

We need new keywords "writeable, writeonly, readable, readonly, dseg, code,
heap, heap[] "

I know, it just "first step view" on the problem, maybe someone see how to
reduce the keywords set, but remain all we need?

--
Maksim A Polyanin
Feb 4 '07 #37

P: n/a
Grizlyk wrote:
//Tobj -data2
//ptr -data2
const Tobj dseg * ptr; //software constness for Tobj
Sorry, misplaced lines (forget delete them from draft). "dseg" is not the
same as writable.

--
Maksim A Polyanin
Feb 4 '07 #38

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>>>>
Grizlyk wrote:

But if you say, that compiler do not support safe const_cast<in
general,
it is bad.

By and large, there is no such thing as a "safe cast" in C++. Whenever
a cast pops up, chances are you doing something whicked. That's why it
is good that C++ casts are grepable, so that you can audit the code.

Grizlyk wrote:
>>We are not speaking about "safe cast", but writing to readonly memory
and other actions like this is wrong idea, especialy when C++ can easy
test it.

It can test this only at run time. The standard, however, does not
require the implementations to perform this test because it does not want
to mandate this overhead.

No, test can be done at compile time, because cast between
"T heap*" and "T readonly code*" must be disabled.
You are clearly not talking about C++ here, you are talking about some
hypothetical language. About that, I have nothing to say.

>>Describe at least one real or theoretical system, where decaring data as
readonly will be error.

I cannot relate this statement to the talk about ROM and hardware from
before. If you just want to indicate that the compiler is free to put a
piece of data into a read-only segment of memory, you can already use
const.

-1-

Better to say, that compiler is ignoring existance such of special and
useful memory areas, as some kind of readonly/writeonly memory. The using
unqualified C-style pointers can lead to runtime errors, when pointers
from readonly segments will be mixed with ordinary memory.

I am repeating, that to avoid the possible errors:
1. we can refuse using C-style pointers without explicit memory qualifiers
and new/new[]
2. or new/new[] must return user defined classes instead of C-style
pointers 3. or we must invent user-defined operators instead of new/new[]
to create dynamic data

-2-
Maybe explicit memory specifiers can be useful as itself (without
concerning dynamic data problems), they do not disturb systems allocating
only one segment, but allow to other systems manualy place data into
concrete segments, "switching on" hardware memory control.

Let you have (it is real sysytem)

- code1 code segment as can not rw
- code2 code segment as readonly
- data1 data segment as readonly
- data2 data segment as rw
- data3 data segment as writeonly (for your process)

where "Tobj" and "ptr" will be placed in following example?

const Tobj *const ptr;
const Tobj * ptr;
Tobj *const ptr;
Tobj * ptr;

but with explicit memory specification

default segments:

data1 - for const T
data2 - for T

// ! not C++

//Tobj -code2
//ptr -data2
code Tobj *ptr; //error code2 is const
code const Tobj *ptr;

//Tobj -data1
//ptr -data2
const Tobj *ptr;
const_cast<Tobj&>(ptr); //error - data1 readonly
//or compiler will remove Tobj into data2 and print warning
//or compiler will make temporary and print warning

//Tobj -data2
//ptr -data2
writable const Tobj *ptr; //software constness
const_cast<Tobj&>(ptr); //ok

//Tobj -data2
//ptr -data2
const Tobj dseg * ptr; //software constness for Tobj

//Tobj -data2
//ptr -data1
Tobj *const ptr;

//Tobj -data2
//ptr -data2
Tobj *const writable ptr; //software constness for ptr

//Tobj -data2
//ptr -code2
Tobj *code ptr; //error - code is
readonly
Tobj *const code writeable ptr; //error - no writeable code seg
Tobj *const code ptr;

We need new keywords "writeable, writeonly, readable, readonly, dseg,
code, heap, heap[] "
I never felt this need. And quite honestly, I don't think those keywords
solve any problem that comes up in my codebase.

I know, it just "first step view" on the problem, maybe someone see how to
reduce the keywords set, but remain all we need?
Maybe you should take these issues over to comp.std.c++. That is where
proposals to change the standard are highly on-topic and will get better
responses.
Best

Kai-Uwe Bux
Feb 4 '07 #39

P: n/a
Kai-Uwe Bux wrote:
>
>>>Grizlyk wrote:

But in the case of const_cast<compiler "know"
what you are doing and can trace you actions, so compiler
_must_ check - is the object placed in writable memory
or not - if not or not sure, it can make temporary
or print error/warning.

It can test this only at run time. The standard, however,
does not require the implementations to perform this test
because it does not want to mandate this overhead.

No, test can be done at compile time, because cast between
"T heap*" and "T readonly code*" must be disabled.

You are clearly not talking about C++ here, you are talking
about some hypothetical language. About that, I have nothing
to say.
I want to say, that i think that compiler can do static type checking, and
const_cast<allow to compiler to do static type checking.

If you can not take my explanation, make your own explanation, but it must
be explanaiton, something lager than "it can not because can not".
>I know, it just "first step view" on the problem, maybe someone see how
to
reduce the keywords set, but remain all we need?

Maybe you should take these issues over to comp.std.c++. That is where
proposals to change the standard are highly on-topic and will get better
responses.

I think pepole who are not close to standard can have own opinion about C++
memory usage :).

--
Maksim A Polyanin
Feb 4 '07 #40

P: n/a
Grizlyk wrote:
Kai-Uwe Bux wrote:
>>
>>>>Grizlyk wrote:
>
But in the case of const_cast<compiler "know"
what you are doing and can trace you actions, so compiler
_must_ check - is the object placed in writable memory
or not - if not or not sure, it can make temporary
or print error/warning.

It can test this only at run time. The standard, however,
does not require the implementations to perform this test
because it does not want to mandate this overhead.

No, test can be done at compile time, because cast between
"T heap*" and "T readonly code*" must be disabled.

You are clearly not talking about C++ here, you are talking
about some hypothetical language. About that, I have nothing
to say.

I want to say, that i think that compiler can do static type checking, and
const_cast<allow to compiler to do static type checking.

If you can not take my explanation, make your own explanation, but it must
be explanaiton, something lager than "it can not because can not".
If it was clear _what_ you want explained, I would be happy to provide an
explanation to the best of my ability. However, what a compiler for a
hypothetical language where

T heap*

and

T readonly code*

is valid syntax could do at compile time or not, is something I cannot
explain. I have no such compiler and I do not know any such language.

>>I know, it just "first step view" on the problem, maybe someone see how
to
reduce the keywords set, but remain all we need?

Maybe you should take these issues over to comp.std.c++. That is where
proposals to change the standard are highly on-topic and will get better
responses.


I think pepole who are not close to standard can have own opinion about
C++ memory usage :).
Maybe. However, programs based upon those opinions detached from the
standard run a high risk of exhibiting undefined behavior.
All in all, I have the feeling that we are caught in some serious
misunderstanding about the topic. I just dropped in to explain the rational
behind the decision of the standard to treat

void f ( int );

and

void f ( const int );

as identical function signatures.

You, on the other hand, seem to be concerned with an overhaul of C++ of much
larger scale that would introduce seven(!) new keywords. I have no basis to
form any opinion on that other than that I do not really see which problem
you are trying to solve. If you put together a consistent proposal for
changing the standard with a clear exposition of the current shortcomings
of C++ that you are trying to fix, it would be much easier for me (and
presumably anybody else) to say something meaningfull about it. (If you
decide to do so, it might be good to start a new thread. It also might be
good to put it into comp.std.c++.)
Sorry for not being helpful
and best regards

Kai-Uwe Bux
Feb 4 '07 #41

P: n/a
Andrey Tarasevich wrote:
Kai-Uwe Bux wrote:
>...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged.
I am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
...

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.
If the int that was passed was initially declared const, the compiler
doesn't have to care about the called function's content, because in that
case, a const_cast invokes undefined behiavor.

Feb 5 '07 #42

P: n/a
Rolf Magnus wrote:
>>...
Hm, you could use

void foo ( const int &, const int & );
void bar ( const int &, const int & );

and the compiler could detect that ints are small and not inheritable and
then decide to put copies on the stack that surely will remain unchanged.
I am not sure whether current C++ compilers would do this kind of
optimization or whether they will blindly push addresses onto the stack.
...

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

If the int that was passed was initially declared const, the compiler
doesn't have to care about the called function's content, because in that
case, a const_cast invokes undefined behiavor.
...
Firstly, in general case the referent might not by declared 'const'. Modifying a
non-const object through a const reference is well defined.

Secondly, if the referent is actually declared const, it isn't const_cast that
invokes the UB. It is the actual modification attempt that does that. The
const_cast itself is prefectly well defined even in that case.

--
Best regards,
Andrey Tarasevich
Feb 5 '07 #43

P: n/a
JLS
On Feb 2, 8:41 am, "Sylvester Hesp" <s.h...@oisyn.nlwrote:
"Grizlyk" <grizl...@yandex.ruwrote in messagenews:ep*********@aioe.org...
Anonymous wrote:
char const* MyClass::errToText(int err) const
Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const

The parameter is local for the function, nobody's going to care whether that
int is const or not. In fact, the standard doesn't care either. These two
function declarations declare the same function:

void foo(int);
void foo(const int);

- Sylvester
I care.

Just because it is a small method, doesn't mean one should use good
coding practices.

It would also be better to avoid char *s at all and use a string
class.

Feb 5 '07 #44

P: n/a
JLS
On Feb 2, 1:43 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
Grizlyk wrote:
Sylvester Hesp wrote:
>Anonymous wrote:
>>char const* MyClass::errToText(int err) const
>Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const
The parameter is local for the function, nobody's going to care whether
that int is const or not. In fact, the standard doesn't care either.
It is bad only for standard, because it is really different function for
user.

Not this one, this is only different for the implementor of the function:
the user passes by value and keeps the original anyway. In fact, the client
code has no way to observe from the outside, whether the parameter is
modified by the function internally.
Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying for
some functions.

Not this one. This one would just tie down the hands of implementors of the
function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of the
result by modifying i internally. Tough luck. That is why the standard is
well-advised to say:
These two function declarations declare the same function:
void foo(int);
void foo(const int);

Note that the situation is completely different for parameters passed by
reference.

Best

Kai-Uwe Bux
That is why you declare the method in the .h file as

void foo(int)

and define the method in the .cpp file as

void foo(const int myInt)

because as far as the interface is concerned, the const doesn't
matter. As far as the method is concerned, myInt is const.

Or do you not bother to use const on any local variable?

Feb 5 '07 #45

P: n/a
JLS wrote:
On Feb 2, 1:43 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
>Grizlyk wrote:
Sylvester Hesp wrote:
Anonymous wrote:
>>>char const* MyClass::errToText(int err) const
>>Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const
>The parameter is local for the function, nobody's going to care
whether that int is const or not. In fact, the standard doesn't care
either.
It is bad only for standard, because it is really different function
for user.

Not this one, this is only different for the implementor of the function:
the user passes by value and keeps the original anyway. In fact, the
client code has no way to observe from the outside, whether the parameter
is modified by the function internally.
Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying
for some functions.

Not this one. This one would just tie down the hands of implementors of
the function. Suppose you declared

int f ( const int i );

and at some point you realize that you can speed up the computation of
the result by modifying i internally. Tough luck. That is why the
standard is well-advised to say:
>These two function declarations declare the same function:
>void foo(int);
void foo(const int);

Note that the situation is completely different for parameters passed by
reference.

Best

Kai-Uwe Bux

That is why you declare the method in the .h file as

void foo(int)

and define the method in the .cpp file as

void foo(const int myInt)

because as far as the interface is concerned, the const doesn't
matter. As far as the method is concerned, myInt is const.

Or do you not bother to use const on any local variable?
I think, I never had a need for a local constant. When I declare local
variables then I want to change them sometime later. But that might be due
to the kind of code I deal with. In my code, magic numbers and such are by
and large not local.

As for the parameter, I would not declare it const just because the
algorithm I choose for the implementation coincidentally happens not to
chance the parameter. In such a case, the const would not convey intend.
Best

Kai-Uwe Bux
Feb 6 '07 #46

P: n/a

Kai-Uwe Bux wrote:
>
Grizlyk wrote:
>Kai-Uwe Bux wrote:
>>>
>Grizlyk wrote:
>>
>But in the case of const_cast<compiler "know"
>what you are doing and can trace you actions, so compiler
>_must_ check - is the object placed in writable memory
>or not - if not or not sure, it can make temporary
>or print error/warning.
>
It can test this only at run time. The standard, however,
does not require the implementations to perform this test
because it does not want to mandate this overhead.

No, test can be done at compile time, because cast between
"T heap*" and "T readonly code*" must be disabled.

You are clearly not talking about C++ here, you are talking
about some hypothetical language. About that, I have nothing
to say.

I want to say, that i think that compiler can do static type checking,
and
const_cast<allow to compiler to do static type checking.

If you can not take my explanation, make your own explanation, but it
must
be explanaiton, something lager than "it can not because can not".

If it was clear _what_ you want explained, I would be happy to provide an
explanation to the best of my ability. However, what a compiler for a
hypothetical language where
...
is valid syntax could do at compile time or not, is something I cannot
explain. I have no such compiler and I do not know any such language.
Well, I repeat it again: support C++ "T heap*" or not does no metter here.
Expression "T heap*" has been used by me to make differences sharper (i see
i have not reached my goal). The question is: "const_cast<allow compiler
to test writeable memory at compile time, not at run time", but you do not
agree with it. And I do not know why are you thinking so.

>I think people who are not close to standard can have own opinion about
C++ memory usage :).

Maybe. However, programs based upon those opinions detached from the
standard run a high risk of exhibiting undefined behavior.
Sometimes to use standard successfully we need not only well know the part
of it, but be able to explain why the part looks as is. For many people it
is true, at least.

All in all, I have the feeling that we are caught in some serious
misunderstanding about the topic. I just dropped in to explain the
rational
behind the decision of the standard to treat

void f ( int );

and

void f ( const int );

as identical function signatures.
Signatures yes, maybe due to ambiguous between int and const int cast. But i
have spoken that const as parameter is useful in regardless to signatures.

You, on the other hand, seem to be concerned with an overhaul of C++ of
much
larger scale that would introduce seven(!) new keywords.
Seven? No, much more :) But this is "collections", we can not count them
separatedly as if each of them is new independent keyword. Really we need
only one "collection" for your counted "seven(!) new keywords", because if
we need explicit memory specification, we need exactly as many keywords, as
many number of types of memory we have.

I have no basis to
form any opinion on that other than that I do not really see which problem
you are trying to solve.
I know the music - "i have no problem" :). It is so easy to try delete auto
or static memory and find the problem after long time, when program has
marked as "debugged and ready to use".

Also we sometimes need to explicit control memory placement (for low-level
programming). You of course can say, that all that no need exactly to
anybody is just "implementation depended" but it is not true, because for
some different implementation, having the same hardware, we will get
non-portable code doing the same. Especially if it is so easy for compiler
to implement the portability. I agree, some of the possible improvements is
not "life or death question", we can live without it.

Sorry for not being helpful
and best regards
All ok. Thanks for your reply.

--
Maksim A. Polyanin

"In thi world of fairy tales rolls are liked olso"
/Gnume/
Feb 6 '07 #47

P: n/a
JLS
On Feb 5, 6:50 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
JLS wrote:
On Feb 2, 1:43 pm, Kai-Uwe Bux <jkherci...@gmx.netwrote:
Grizlyk wrote:
Sylvester Hesp wrote:
Anonymous wrote:
>>char const* MyClass::errToText(int err) const
>Say "const" if you are not going to change variable
char const* MyClass::errToText(const int err) const
The parameter is local for the function, nobody's going to care
whether that int is const or not. In fact, the standard doesn't care
either.
It is bad only for standard, because it is really different function
for user.
Not this one, this is only different for the implementor of the function:
the user passes by value and keeps the original anyway. In fact, the
client code has no way to observe from the outside, whether the parameter
is modified by the function internally.
Explicit const type declaration is allow to you to detect errors in
your code, and can help to compiler to reduce unnecessary data copying
for some functions.
Not this one. This one would just tie down the hands of implementors of
the function. Suppose you declared
int f ( const int i );
and at some point you realize that you can speed up the computation of
the result by modifying i internally. Tough luck. That is why the
standard is well-advised to say:
These two function declarations declare the same function:
void foo(int);
void foo(const int);
Note that the situation is completely different for parameters passed by
reference.
Best
Kai-Uwe Bux
That is why you declare the method in the .h file as
void foo(int)
and define the method in the .cpp file as
void foo(const int myInt)
because as far as the interface is concerned, the const doesn't
matter. As far as the method is concerned, myInt is const.
Or do you not bother to use const on any local variable?

I think, I never had a need for a local constant. When I declare local
variables then I want to change them sometime later. But that might be due
to the kind of code I deal with. In my code, magic numbers and such are by
and large not local.

As for the parameter, I would not declare it const just because the
algorithm I choose for the implementation coincidentally happens not to
chance the parameter. In such a case, the const would not convey intend.

Best

Kai-Uwe Bux- Hide quoted text -

- Show quoted text -
There are other reasons to use const, other than for magic numbers.
THere is never a "need" to use const, just a high desireability.

Reasons to use const?
1. Compiler enforced, self-documenting code.
2. Allows the compiler to automatically detect some errors.

While one could argue that the use of const is of less import, the
smaller the scope of the variable, the import is never completely
eliminated. Just because you have never noticed a bug that the
compiler would have caught with the proper use of const, does not
eliminate the possibility that those bugs exist or have existed. One
type of bug that is evidently very common (as simple stupid bugs go)
is the problem with

if (a = b)

where the programmer meant comparison, rather than assignment. If a
were const, this bug shows up like a sore thumb. Of course, this isn't
the only bug that can be prevented, by the use of const, just one of
many. Other examples I've seen are when the programmer types the wrong
variable name, let's say in an assignment. Yes, it is a stupid little
bug that will eventually be discovered by unit testing or in a code
review. By why not let the compiler catch it immediately?

This is my argument for using const. Some number of bugs will be
caught using const. It makes the code clearer and more understandable.
There is no down side, so why not use it?

Feb 6 '07 #48

P: n/a

Rolf Magnus wrote:
>>>
void foo ( const int &, const int & );
void bar ( const int &, const int & );

Without some non-trivial analysis of the implementation of the function,
the compiler has no other choice but to push addresses onto the stack.
It has to keep in mind the possibility of user using 'const_cast' in
order to cast away the constness and modify the object the reference is
referring to.

If the int that was passed was initially declared const, the compiler
doesn't have to care about the called function's content, because in that
case, a const_cast invokes undefined behiavor.
Maybe, if compiler do not inline function, it could mark function using
const_cast<for its const referenced parameter as requested the reference
to be placed in writable memory, and at link stage linker will detect the
usage of readonly memory in const_cast<>. It is better than "undefined
behaviour". Consider

- 1.cpp -
void foo ( const int &); // foo$const_int&$

void test()
{
//readonly segment
static const int i=0;
foo(i); // foo$const_int&%readonly$
//writable segment
static int k=0;
foo(i); // foo$const_int&%writable$
}
- 1.cpp -

- 2.cpp -
void foo ( const int & p) // foo$const_int&%writable$
{
int &tmp=const_cast<int&>(p);
}
- 2.cpp -

- 3.cpp -
void foo ( const int & ) // foo$const_int&%readonly$
{
}
- 3.cpp -

Linking 1.cpp + 2.cpp we will get link time error, because external
"foo$const_int&%readonly$" was not found.

Linking 1.cpp + 2.cpp + 3.cpp we will get link time error, because
"foo$const_int&%readonly$" and "foo$const_int&%writable$" can not be public
simultaneously.

Linking 1.cpp + 3.cpp we get sucsessful link, because public
"foo$const_int&%readonly$" can be used as external
"foo$const_int&%writable$".

--
Maksim A. Polyanin

"In thi world of fairy tales rolls are liked olso"
/Gnume/
Feb 6 '07 #49

P: n/a
Grizlyk schrieb:
Well, I repeat it again: support C++ "T heap*" or not does no metter here.
Expression "T heap*" has been used by me to make differences sharper (i see
i have not reached my goal). The question is: "const_cast<allow compiler
to test writeable memory at compile time, not at run time", but you do not
agree with it. And I do not know why are you thinking so.
void somefunction(const char* cstr)
{
char* str = const_cast<char*>(cstr);
// write to str
}

void test()
{
char arr[] = "string1";

somefunction(arr);
somefunction("string2");
}

The compiler /cannot/ test at compile time, if memory is readonly or not.
It /may/ work in one compilation unit, but it won't work across compilation
units or from a library.

The compiler can only warn in the cases it sees the function body, but why
should it? The programmer is supposed to know when he is allowed to use a
const_cast.

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Feb 6 '07 #50

83 Replies

This discussion thread is closed

Replies have been disabled for this discussion.