C++:将容器转换为不同但兼容类型的容器

peo*_*oro 7 c++ containers casting

它经常发生在我身上有AA容器C的类型(或任何类型的包装类,甚至是智能指针)T1,并希望这种转换C<T1>C<T2>,其中T2是兼容的T1.

C++不允许我直接转换整个容器,并且强制a reinterpet_cast会导致未定义的行为,所以我需要创建一个新的C<T2>容器并使用生成的C<T1>项目重新填充它T2.这种操作在时间和空间上都非常昂贵.

而且许多情况下,我敢肯定,强制reinterpret_cast将正常工作与任何编译器编译的代码曾经存在,例如,当T2T1 const时,或者T1T2是指针.

是否有转换任何清洁和高效的方式C<T1>C<T2>
例如,一个container_cast运算符(/ function?)创建并重新填充C<T2>if和only,如果它不是二进制兼容的C<T1>

Dav*_*eas 5

除了其他人处理的所有其他问题之外:

  • 转换并不意味着相同的内存占用(想想转换操作......)
  • 模板类的潜在专业化(问题中的容器,但从编译器的角度来看,容器只是另一个模板),即使类型本身是二进制兼容的
  • 同一模板的不同实例化的不相关性(对于一般情况)

该方法存在一个根本不属于技术性的基本问题。假设苹果是一种水果,那么装水果的容器就不是装苹果的容器(简单地演示过),装苹果的容器也不是装水果的容器。尝试将西瓜放入一盒苹果中!

转到更多技术细节,并专门处理甚至不需要转换的继承(派生对象已经是基类的对象),如果允许将派生类型的容器强制转换为基类型,那么您可以将无效元素添加到容器中:

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!!!
Run Code Online (Sandbox Code Playgroud)

最后一行完全正确:您可以将 a 添加watermelon到 a vector<fruit*>。但最终的结果是您将 a 添加watermelon到 a 中vector<apple*>,这样做就破坏了类型系统。

并非所有乍一看很简单的东西实际上都是理智的。int **这与为什么你不能将 an 转换为 a的原因类似const int **,即使你的第一个想法是应该允许它。事实上,允许这样做会破坏语言(在本例中为 const 正确性):

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!!!
Run Code Online (Sandbox Code Playgroud)

这让我们回到您在另一个答案的评论之一中提供的示例(为了证明这一点,我将使用向量而不是集合,因为集合内容是不可变的):

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
Run Code Online (Sandbox Code Playgroud)