简体   繁体   中英

Non-trivial example of undefined behavior with const_cast

The following code is, as far as I understand it, undefined behavior according to the c++ standard (section 7.1.5.1.4 [dcl.type.cv]/4 in particular).

#include <iostream>

struct F;
F* g;

struct F {
    F() : val(5)
    {
        g = this;
    }
    int val;
};


const F f;

int main() {
    g->val = 8;
    std::cout << f.val << std::endl;
}

However, this prints '8' with every compiler and optimization setting I have tried.

Question : Is there an example that will exhibit unexpected results with this type of "implicit const_cast"?

I am hoping for something as spectacular as the results of

#include <iostream>
int main() {
    for (int i = 0; i <=4; ++i)
        std::cout << i * 1000000000 << std::endl;
}

on, eg, gcc 4.8.5 with -O2

EDIT : the relevant section from the standard

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.

In reply to the comment suggesting a duplicate; it is not a duplicate because I am asking for an example where "unexpected" results occur.

Not as spectacular:

fh (guards omitted):

struct F;
extern F* g;

struct F {
    F() : val(5)
    {
        g = this;
    }
    int val;
};

extern const F f;
void h();

TU1:

#include "f.h"
// definitions
F* g;
const F f;
void h() {}    

TU2:

#include "f.h"
#include <iostream>
int main() {
    h(); // ensure that globals have been initialized
    int val = f.val;
    g->val = 8;
    std::cout << (f.val == val) << '\n';
}

Prints 1 when compiled with g++ -O2 , and 0 when compiled with -O0 .

The main case of "undefined" behavior would be that typically, if someone sees const , they will assume that it does not change. So, const_cast intentionally does something that many libraries and programs would either not expect to be done or consider as explicit undefined behavior. It's important to remember that not all undefined behavior comes from the standard alone, even if that is the typical usage of the term.

That said, I was able to locate a place in the standard library where such thinking can be applied to do something I believe would more narrowly be considered undefined behavior: generating an std::map with "duplicate keys":

#include "iostream"
#include "map"

int main( )
{
    std::map< int, int > aMap;

    aMap[ 10 ] = 1;
    aMap[ 20 ] = 2;

    *const_cast< int* >( &aMap.find( 10 )->first ) = 20;

    std::cout << "Iteration:" << std::endl;
    for( std::map< int,int >::iterator i = aMap.begin(); i != aMap.end(); ++i )
        std::cout << i->first << " : " << i->second << std::endl;

    std::cout << std::endl << "Subscript Access:" << std::endl;
    std::cout << "aMap[ 10 ]" << " : " << aMap[ 10 ] << std::endl;
    std::cout << "aMap[ 20 ]" << " : " << aMap[ 20 ] << std::endl;

    std::cout << std::endl << "Iteration:" << std::endl;
    for( std::map< int,int >::iterator i = aMap.begin(); i != aMap.end(); ++i )
        std::cout << i->first << " : " << i->second << std::endl;
}

The output is:

Iteration:
20 : 1
20 : 2

Subscript Access:
aMap[ 10 ] : 0
aMap[ 20 ] : 1

Iteration:
10 : 0
20 : 1
20 : 2

Built with g++.exe (Rev5, Built by MSYS2 project) 5.3.0 .

Obviously, there is a mismatch between the access keys and the key values in the stored pairs. It also seems that the 20:2 pair is not accessible except via iteration.

My guess is that this is happening because map is implemented as a tree. Changing the value leaves it where it initially was (where 10 would go), so it does not overwrite the other 20 key. At the same time, adding an actual 10 does not overwrite the old 10 because on checking the key value, it's not actually the same

I do not have a standard to look at right now, but I would expect this violates the definition of map on a few levels.

It might also lead to worse behavior, but with my compiler/OS combo I was unable to get it to do anything more extreme, like crash.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM