C ++: converting a container to a container of a different but compatible type

It often happens to me that T1there is a container for a type C(or some kind of wrapper class, even smart pointers), and you want to convert one C<T1>to C<T2>where it is T2compatible with T1.

C ++ does not allow me to directly convert the entire container, and forcing reinterpet_castwill lead to undefined behavior, so I will need to create a new container C<T2>and repeat it using C<T1>cast as elements T2. This operation can be quite expensive, both in time and in space.

In addition, in many cases, I am sure that forcing reinterpret_castwill work with code compiled by any compiler that has ever existed, for example, when T2there are T1 constor when T1they T2are pointers.

Is there any clean and efficient way to convert C<T1>to C<T2>?
For example, the operator container_cast(/ function?), Which creates and repopulates C<T2>if and only if it is not binary compatible with C<T1>?

+5
source share
8 answers

In addition to all other issues addressed by others:

  • conversion does not imply the same amount of memory (think conversion operations ...)
  • ( , - ), .
  • ( )

, , . , , - ( ), - . !

, , ( ), , :

class fruit {};
class apple : public fruit {};
class watermelon : public fruit {};
std::vector<apple*> apples = buy_box_of_apples();
std::vector<fruit*> & fruits = reinterpret_cast< std::vector<fruit*>& >(apples);
fruits.push_back( new watermelon() ); // ouch!!!

: watermelon vector<fruit*>. , watermelon vector<apple*>, .

, , . , int ** const int **, , . , ( const correctness):

const int a = 5;
int *p = 0;
int **p1 = &p;       // perfectly fine
const int **p2 = p1; // should this be allowed??
*p2 = &a;            // correct, p2 points to a pointer to a const int
**p1 = 100;          // a == 100!!!

, , ( , , , ):

std::vector<int*> v1;
std::vector<const int*> &v2 = v1; // should this be allowed?
const int a = 5;
v2.push_back( &a );  // fine, v2 is a vector of pointers to constant int
                     // rather not: it IS a vector of pointers to non-const ints!
*v1[0] = 10;         // ouch!!! a==10
+3

, , reinterpret_cast

, . , , , . , -, , , .

, .

, , . . , .

+4

C<T1> c1;
/* Fill c1 */
C<T2> c2(c1.begin(), c1.end());

. , , , .

- reinterpret_cast , - .

+3

, , . , , , .

C<int> C<short>, , :

class C_int_ {
    //...
};

class C_short_ {
    //...
};

, , , . (, C-cast), - , , , - .

, . .

+2

. , , vector<bool>, , vector<int> , .

+1

, - reinterpret_cast<>.

, (, std::vector) C-, C<T1> T1[], C<T2> T2[]. T1 T2 (, T2 -), T1[] T2[], .

, C<T1> C<T2> .

( , , C<T1> , C<T2>)

., , .

+1

, .

(!) , ++ * . undefined, , , ( , , ).

, , !

*: , . : float int - 4 , .


++: , : struct A{ int a[1000000]; }; struct B{ int a[1000000]; };.

A, B. :

  • , : , , . () .

  • , - ++ - , . , . , , , A B -, , , , ( GCC 4.5 Clang 2.8 , STL/boost).

  • , , . int const int ( int* a char*), , ( , ) .


, object_static_cast, , , , , , ; , .

, . , SO .

, , :

// NOTE: this function cannot be safely implemented without compiler
//       explicit support. It dangerous, don't trust it.
template< typename T1, typename T2 >
struct is_binary_compatible : public boost::false_type{};

sais (, ), (, boost::has_virtual_destructor, ).

object_static_cast:

namespace detail
{
    template< typename T1, typename T2, bool >
    struct object_static_cast_class {
        typedef T1 ret;
        static ret cast( const T2 &in ) {
            return T1( in );
        }
    };

    // NOTE: this is a dangerous hack.
    //       you MUST be sure that T1 and T2 is binary compatible.
    //       `binary compatible` means 
    //       plus RTTI could give some issues
    //       test this any time you compile.
    template< typename T1, typename T2 >
    struct object_static_cast_class< T1, T2, true > {
        typedef T1& ret;
        static ret cast( const T2 &in ) {
            return *( (T1*)& in ); // sorry for this :(
        }
    };

}

// casts @in (of type T2) in an object of type T1.
// could return the value by value or by reference
template< typename T1, typename T2 >
inline typename detail::object_static_cast_class< T1, T2,
        is_binary_compatible<T1, T2>::value >::ret
    object_static_cast( const T2 &in )
{
    return detail::object_static_cast_class< T1, T2,
            is_binary_compatible<T1, T2>::value >::cast( in );
};

struct Data {
    enum { size = 1024*1024*100 };
    char *x;

    Data( ) {
        std::cout << "Allocating Data" << std::endl;
        x = new char[size];
    }
    Data( const Data &other ) {
        std::cout << "Copying Data [copy ctor]" << std::endl;
        x = new char[size];
        std::copy( other.x, other.x+size, x );
    }
    Data & operator= ( const Data &other ) {
        std::cout << "Copying Data [=]" << std::endl;
        x = new char[size];
        std::copy( other.x, other.x+size, x );
        return *this;
    }
    ~Data( ) {
        std::cout << "Destroying Data" << std::endl;
        delete[] x;
    }
    bool operator==( const Data &other ) const {
        return std::equal( x, x+size, other.x );
    }

};
struct A {
    Data x;
};
struct B {
    Data x;

    B( const A &a ) { x = a.x; }
    bool operator==( const A &a ) const { return x == a.x; }
};

#include <cassert>
int main( ) {
    A a;
    const B &b = object_static_cast< B, A >( a );

    // NOTE: this is NOT enough to check binary compatibility!
    assert( b == a );

    return 0;
}

:

$ time ./bnicmop 
Allocating Data
Allocating Data
Copying Data [=]
Destroying Data
Destroying Data

real    0m0.411s
user    0m0.303s
sys     0m0.163s

(!) main():

// WARNING! DANGEROUS! DON'T TRY THIS AT HOME!
// NOTE: using these, program will have undefined behavior: although it may
//       work now, it might not work when changing compiler.
template<> struct is_binary_compatible< A, B > : public boost::true_type{};
template<> struct is_binary_compatible< B, A > : public boost::true_type{};

:

$ time ./bnicmop 
Allocating Data
Destroying Data

real    0m0.123s
user    0m0.087s
sys     0m0.017s

( 3 !), (!) , , , , .

, , undefined -behaving object_static_cast , , , .


, : (, , , ) .

+1

. , , . , ptr_container, . , boost ptr_containers void* , .

, . , boost::shared_ptr static_pointer_cast dynamic_pointer_cast.

0

All Articles