将std::map的std::pair向下转换为子类是否属于未定义行为?
结论:这种操作属于未定义行为,完全不合法
为什么不行?
- 反向转型违反C++类型规则:C++标准只允许将子类的指针/引用安全向上转换到它的公共基类。反过来,把基类对象强制转换成子类类型,不管子类有没有新增成员,都是标准明确禁止的行为。
std::map里存储的是std::pair<const std::string, std::string>对象,本质上不是Concatenator对象,强行“冒充”子类类型属于类型欺骗,标准不会为这种行为的结果负责。 - 内存布局无保证:哪怕你的子类没有新增成员,C++标准也没有规定“子类必须和基类内存布局完全一致”。编译器可能出于优化、ABI要求等原因对子类布局做调整,看起来一致只是特定编译器下的巧合,换个编译器或编译选项就可能出问题。
更安全的替代方案
没必要搞这种危险的强制转换,有两种更稳妥的方式实现需求:
方案1:写一个自由函数
#include <iostream> #include <map> #include <string> std::string concatenate(const std::pair<const std::string, std::string>& p) { return p.first + ", " + p.second; } int main() { std::map<std::string, std::string> m{{"hello", "world"}}; std::cout << concatenate(*m.begin()) << std::endl; }
方案2:用包装类持有引用
#include <iostream> #include <map> #include <string> class Concatenator { private: const std::pair<const std::string, std::string>& pair_ref; public: explicit Concatenator(const std::pair<const std::string, std::string>& p) : pair_ref(p) {} operator std::string() const { return pair_ref.first + ", " + pair_ref.second; } }; int main() { std::map<std::string, std::string> m{{"hello", "world"}}; Concatenator c(*m.begin()); std::cout << std::string{c} << std::endl; }
内容的提问来源于stack exchange,提问作者phinz
相关产品推荐
相关产品推荐

