Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Const_cast as undefined behavior?

Reply
Thread Tools

Const_cast as undefined behavior?

 
 
Nephi Immortal
Guest
Posts: n/a
 
      01-11-2013
On Thursday, January 10, 2013 2:10:44 PM UTC-6, Andrey Tarasevich wrote:
> On 1/9/2013 5:56 PM, Rui Maciel wrote:
>
> > Ian Collins wrote:

>
> >

>
> >> That doesn't contradict what was written. The write operation results

>
> >> in undefined behaviour, not the cast operation.

>
> >

>
> > What leads to the undefined behavior is the removal of the safeguards

>
> > against abusing that write operation.


I thought I want to add. Let’s look at my code below.

int main()
{
const char* data = "0123456789";

const_cast< char* >( data )[ 2 ] = 'A';

return 0;
}

C++ Compiler will compile without any problems, but it is unaware of the 4Kmemory page if it is marked as read only, but not read-write. The undefined behavior is possible. If you use Microsoft’s Virtual Memory functionsor Heap Memory functions, you have to be careful to mark either read only or read-write.

The Visual C++ will automatically compiles all constant strings into 4K memory page and it marks them as read only. What happen if you take away constant string by using const_cast? The C++ Compiler will compile fine, but the program will crash during the execution. The error dialog box will appear to the screen as saying violation memory access. You are not permitted to modify constant strings in read only 4K memory page.

I am supposed to take your advice. I should use two classes as const classand non-const class instead of one const / non-const class.




>
>
>
> Well, ultimately that's no different that stating the the very design of
>
> C++ language is what _really_ leads to all kinds of undefined behavior.
>
> And we have no shortage of individuals who just love to spread this sort
>
> of wisdom around various places on the net and outside of it.
>
>
>
> While this might be an interesting topic for some people, it is not
>
> really what the question is about.
>
>
>
> --
>
> Best regards,
>
> Andrey Tarasevich


 
Reply With Quote
 
 
 
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      01-11-2013
On Thu, 10 Jan 2013 18:36:10 -0800, Nephi Immortal wrote:

>
> I am supposed to take your advice. I should use two classes as const
> class and non-const class instead of one const / non-const class.
>

You can still use only one class, but you have to ensure it can not be
mis-used to modify a const object.

You can do this simply by changing the return value of X::Get to be 'const
Y', like this:

class Y;

class X
{
friend class Y;

public:
X( int data1, int data2 );
const Y Get() const;
Y Set();

private:
int data1;
int data2;
};

class Y
{
public:
Y( X& p );
Y( const Y& r );

int Value1() const;
void Value1( int data );

int Value2() const;
void Value2( int data );

private:
X& pX;
};

X::X( int data1, int data2 ) : data1( data1), data2( data2 ) {
}

const Y X::Get() const
{
return Y( const_cast< X& >( *this ));
}

Y X::Set()
{
return Y( *this );
}

Y::Y( X& p ) : pX( p )
{
}

Y::Y( const Y& r ) : pX( r.pX )
{
}

int Y::Value1() const
{
return pX.data1;
}

void Y::Value1( int data )
{
pX.data1 = data;
}

int Y::Value2() const
{
return pX.data2;
}

void Y::Value2( int data )
{
pX.data2 = data;
}

int main()
{
int number1 = 0, number2 = 0;

const X x1( 5, 10 );
X x( 5, 10 );

number1 = x.Get().Value1();
number2 = x.Get().Value2();

x.Set().Value1( 50 );
//x.Get().Value2( 100 ); /* error: You can only use const members of
Y. That excludes Value1(number) and Value2(number) */

number1 = x1.Get().Value1();
number2 = x1.Get().Value2();

number1 = x1.Get().Value1();
number2 = x1.Get().Value2();

//x1.Set().Value1( 50 ); /* error: You can only use const members of
X. That excludes Set() */
//x1.Get().Value2( 100 ); /* error: You can only use const members of
Y. That excludes Value1(number) and Value2(number) */

number1 = x1.Get().Value1();
number2 = x1.Get().Value2();

return 0;
}
 
Reply With Quote
 
 
 
 
Stuart
Guest
Posts: n/a
 
      01-11-2013
Andrey Tarasevich wrote:
>> As I stated in my answer, it is the attempt to modify a constant object
>> ("... a write operation ...") that produces undefined behavior.
>>
>> `const_cast` itself is a way to create "the pointer, lvalue or pointer
>> to data member" mentioned in the above quote. By itself it does not make
>> any "write operations" through the resultant value. And it does not
>> cause any undefined behavior.


On 01/10/13 Rui Maciel wrote:
> That's not right. What may lead to undefined behavior is having used
> const_cast to remove access restrictions which should always be there and
> should never be taken away. If the const qualifier isn't used irresponsibly
> then the compiler naturally catches the attempt to call non-const member
> functions on a const object, as is expected from him.
>
> Let's be honest here: if you one day stumbled on a bug caused by this sort
> of problem, you would never claim that the const_cast was perfectly fine,
> and that the entire problem was caused by how the "write operation" has been
> poorly designed so that it fails to work when its access restrictions were
> removed.


From this perspective you are right, the source of the evil is
definitely a mis-used const_cast.

However, the C++ Standard chooses to define it a bit differently so that
programmers which have to deal with C APIs can pass const_cast'ed
pointers to the C API without leaving safe ground.

If, however, an implementor of the strlen function decides to
write-access the char* pointer, it would be definitely _his_ fault, not
yours.

This is due to the fact that there is an implied contract between you
and any implementor of strlen: The passed array may only be accessed
through read operations. It's a shortcoming of the C language at the
time that one could not codify this implied contract in the signature of
strlen.

To come to an conclusion: const_casts should be avoided at all costs
unless you are dealing with C APIs. To allow C++ programmers to use C
APIs, not the use of the const_cast should be banned but the use in the
wrong way.

Regards,
Stuart
 
Reply With Quote
 
Tobias Müller
Guest
Posts: n/a
 
      01-11-2013
Nephi Immortal <(E-Mail Removed)> wrote:
> I am supposed to take your advice. I should use two classes as const
> class and non-const class instead of one const / non-const class.


Actually, you gain nothing by combining the two proxy classes into one.
You don't need the setter methods on the getter proxy and vice versa:

class Y_Get
{
public:
Y_Get(const X&);
int value1() const;
int value2() const;
private:
const X& x;
};

class Y_Set
{
public:
Y_Set(X&);
void value1(int);
void value2(int);
private:
X& x;
};

It's not really more code to write.

Tobi
 
Reply With Quote
 
Tobias Müller
Guest
Posts: n/a
 
      01-11-2013
Bart van Ingen Schenau <(E-Mail Removed)> wrote:
> On Thu, 10 Jan 2013 18:36:10 -0800, Nephi Immortal wrote:
>
>>
>> I am supposed to take your advice. I should use two classes as const
>> class and non-const class instead of one const / non-const class.
>>

> You can still use only one class, but you have to ensure it can not be
> mis-used to modify a const object.
>
> You can do this simply by changing the return value of X::Get to be 'const Y'


const X x(5,10);
Y y(x.Get());
y.value1(7);

Since Y has a copy constructor it's still not really safe.

Tobi
 
Reply With Quote
 
Nephi Immortal
Guest
Posts: n/a
 
      01-17-2013
On Friday, January 11, 2013 11:35:53 AM UTC-6, Tobias Müller wrote:
> Bart van Ingen Schenau <(E-Mail Removed)> wrote:
>
> > On Thu, 10 Jan 2013 18:36:10 -0800, Nephi Immortal wrote:

>
> >

>
> >>

>
> >> I am supposed to take your advice. I should use two classes as const

>
> >> class and non-const class instead of one const / non-const class.

>
> >>

>
> > You can still use only one class, but you have to ensure it can not be

>
> > mis-used to modify a const object.

>
> >

>
> > You can do this simply by changing the return value of X::Get to be 'const Y'

>
>
>
> const X x(5,10);
>
> Y y(x.Get());
>
> y.value1(7);
>
>
>
> Since Y has a copy constructor it's still not really safe.

Why isn't it safe? Is it because of reference instead of value?


I made some changes in my code since you said it is unsafe. I have alreadywrapped Y class into X class. Y class is inaccessible. Also, I have added const in Get() so that it can have two consts and do not need const_cast.

Please review my code below. Let me know if my code is safe.

You may notice that I added explicit copy constructor function and destructor function because you can be able to trace step by step in the debugger.

class X
{
private:
struct Y
{
Y( int data1, int data2 );
Y( const Y& right );
~Y();

int Value1() const;
void Value1( int data );

int Value2() const;
void Value2( int data );

int data1;
int data2;
} data;

public:
X( int data1, int data2 );
~X();

const Y Get() const;
const Y& Get();
Y& Set();
};

X::Y::Y( int data1, int data2 ) : data1( data1 ), data2( data2 )
{
}

X::Y::Y( const Y& right ) : data1( right.data1 ), data2( right.data2 )
{
}

X::Y::~Y()
{
}

int X::Y::Value1() const
{
return data1;
}

void X::Y::Value1( int data )
{
data1 = data;
}

int X::Y::Value2() const
{
return data2;
}

void X::Y::Value2( int data )
{
data2 = data;
}

X::X( int data1, int data2 ) : data( Y( data1, data2 ) )
{
}

X::~X()
{
}

const X::Y X::Get() const
{
return data;
}

const X::Y& X::Get()
{
return data;
}

X::Y& X::Set()
{
return data;
}

int main()
{
int number1 = 0, number2 = 0;

// const X x( 5, 10 );
X x( 5, 10 );

number1 = x.Get().Value1();
number2 = x.Get().Value2();

x.Set().Value1( 50 ); // error if you declare const X x( 5, 10 )
x.Set().Value2( 100 ); // error if you declare const X x( 5, 10 )

number1 = x.Get().Value1();
number2 = x.Get().Value2();

x.Get().Value1( 500 ); // error if you declare const X x( 5, 10 )
x.Get().Value2( 1000 ); // error if you declare const X x( 5, 10 )

return 0;
}
 
Reply With Quote
 
Tobias Müller
Guest
Posts: n/a
 
      01-17-2013
Nephi Immortal <(E-Mail Removed)> wrote:
> On Friday, January 11, 2013 11:35:53 AM UTC-6, Tobias Müller wrote:
>> const X x(5,10);
>> Y y(x.Get());
>> y.value1(7);
>>
>> Since Y has a copy constructor it's still not really safe.

> Why isn't it safe? Is it because of reference instead of value?


The copy constructor is fine, that's how copy constructors usually are
defined.
But the fact that it exists enables other people to use it.
However you also cannot delete it, because it is needed to return Y by
value in X::Get() and X::Set().

> I made some changes in my code since you said it is unsafe. I have
> already wrapped Y class into X class.


I think that's a good thing for clarity, but does not fix the problem.

> Y class is inaccessible.


AFAIK that's not possible. To return an object of type Y in a public
method. Y has to be public too.

The only solution I can think of is, make the _constructor_ of Y private
and write "friend class X;" in Y.

> Also, I have added const in Get() so that it can have two consts and do
> not need const_cast.


Now you have two Get() methods, why? I think you should decide whether to
return by reference or value and then be consequent.

const Y Get() const;
Y Set();

or

const Y& Get() const;
Y& Set();

Tobi
 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      01-17-2013
On Thu, 17 Jan 2013 06:48:03 +0000, Tobias Müller wrote:

> Nephi Immortal <(E-Mail Removed)> wrote:
>
>> Y class is inaccessible.

>
> AFAIK that's not possible. To return an object of type Y in a public
> method. Y has to be public too.


There is no problem with returning a private type from a public (member)
function.
The only thing that the caller can't do is name the return type.

X::Y y = x.Get(); // Error. X::Y is private withing this context
x.Get().Value1(); // OK. No private names in sight
auto y = x.Get(); // OK. No private names in sight

> Tobi


Bart v Ingen Schenau
 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      01-17-2013
On Thu, 17 Jan 2013 06:48:03 +0000, Tobias Müller wrote:

> Nephi Immortal <(E-Mail Removed)> wrote:
>
>> Y class is inaccessible.

>
> AFAIK that's not possible. To return an object of type Y in a public
> method. Y has to be public too.


There is no problem with returning a private type from a public (member)
function.
The only thing that the caller can't do is name the return type.

X::Y y = x.Get(); // Error. X::Y is private withing this context
x.Get().Value1(); // OK. No private names in sight
auto y = x.Get(); // OK. No private names in sight

> Tobi


Bart v Ingen Schenau
 
Reply With Quote
 
Bart van Ingen Schenau
Guest
Posts: n/a
 
      01-17-2013
On Thu, 17 Jan 2013 06:48:03 +0000, Tobias Müller wrote:

> Nephi Immortal <(E-Mail Removed)> wrote:
>
>> Y class is inaccessible.

>
> AFAIK that's not possible. To return an object of type Y in a public
> method. Y has to be public too.


There is no problem with returning a private type from a public (member)
function.
The only thing that the caller can't do is name the return type.

X::Y y = x.Get(); // Error. X::Y is private withing this context
x.Get().Value1(); // OK. No private names in sight
auto y = x.Get(); // OK. No private names in sight

> Tobi


Bart v Ingen Schenau
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
const_cast undefined results Simon Bailey C++ 6 10-13-2004 01:45 PM
const_cast S.Senthilvel C++ 4 01-08-2004 06:59 PM
const_cast<> R. Anbeeswaran C++ 7 11-14-2003 12:15 PM
const_cast question drowned C++ 3 08-04-2003 08:51 AM
[help] const_cast Kaspar Minosiants C++ 2 07-21-2003 12:43 PM



Advertisments