Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::any type change leading to illegal access

While testing the examples trough the boost cpp libraries book I noticed that changing the type stored inside a boost::any variable may lead to an illegal access instead of an exception:

good:

boost::any a = 1;
bool *p = boost::any_cast<bool>(&a); // ok, bad cast exception

bad:

boost::any a = std::string { "Boost" };
a = 1;
bool *p = boost::any_cast<bool>(&a); // no exception thrown
std::cout << std::boolalpha << *p << '\n'; // illegal access

My question therefore is: is this a bug as it seems or is it some underlying fact related to templates usage that I am not aware of?

like image 713
Alex C Avatar asked Oct 13 '16 10:10

Alex C


1 Answers

I understand the documentation differently:

Returns: If passed a pointer, it returns a similarly qualified pointer to the value content if successful, otherwise null is returned. If T is ValueType, it returns a copy of the held value, otherwise, if T is a reference to (possibly const qualified) ValueType, it returns a reference to the held value.

Throws: Overloads taking an any pointer do not throw; overloads taking an any value or reference throws bad_any_cast if unsuccessful.

So:

  1. The success or failure of the conversion depends on the stored type and target type.

  2. The manifestation of failure though, depends on whether you pass a pointer to any_cast or not. If you pass a pointer, the manifestation is a nullptr; otherwise, the manifestation is an exception.

Consider for example this code:

#include <boost/any.hpp>
#include <iostream>

int main() {
    boost::any a = 1;

This seems to contradict the statement in your question - since it takes a pointer, it doesn't throw, but the pointer is nullptr:

    bool *p = boost::any_cast<bool>(&a); 
    // Prints true
    std::cout << std::boolalpha << (p == nullptr) << std::endl;

This is how it looks when it's OK:

    int *q = boost::any_cast<int>(&a); 
    // Prints false
    std::cout << std::boolalpha << (q == nullptr) << std::endl;

This throws, because it doesn't take a pointer:

    try {
        boost::any_cast<bool>(a);
    }
    catch(...) {
        std::cout << "caught" << std::endl;
    }

Same for a string stored type:

    a = std::string { "Boost" }; 
    p = boost::any_cast<bool>(&a); 
    // Prints true
    std::cout << std::boolalpha << (p == nullptr) << std::endl;
    try {
        boost::any_cast<bool>(a);
    }
    catch(...) {
        std::cout << "caught again" << std::endl;
    }
}
like image 123
Ami Tavory Avatar answered Sep 29 '22 22:09

Ami Tavory