【问题标题】:reinterpret_cast between std::unordered_mapstd::unordered_map 之间的 reinterpret_cast
【发布时间】:2017-05-21 21:09:36
【问题描述】:

我有以下unordered_maps:

 struct a{
        std::string b;
    };

    int main()
    {
        std::unordered_map<std::string, std::string> source;
        source["1"] = "Test";
        source["2"] = "Test2";

        std::unordered_map<std::string, a> dest = *reinterpret_cast<std::unordered_map<std::string, a>*>(&source);

        std::cout << dest["1"].b << std::endl;
        std::cout << dest["2"].b << std::endl;

    }

使用reinterpret_cast 我将source 转换为dest。这是因为struct a 只包含std::string

我的问题:这实际上是一个好的做法吗? GCC 产生以下警告:

取消引用类型双关指针会破坏严格的别名规则

我可以放心地忽略这个吗?或者只转换 STL 容器的原始字节有什么潜在的缺点吗?

(cpp.sh/5r2rh)

【问题讨论】:

  • 你有read about strict aliasing吗?如果编译器给你一个警告,那是有原因的,它告诉你你正在做一些你不应该做的事情。
  • 好的,所以在这种情况下 reinterpret_cast 不是一个选项。 (尽管我在不同的 -O 级别上使用 MSVC 和 GCC 编译它并且效果很好)除了实际复制地图还有其他方法吗?
  • 复制地图的唯一标准和好的方法是循环遍历第一个元素中的每个元素并将其添加到第二个元素。除非源地图非常大,或者您必须每秒执行数百次,否则它不会真正被注意到。

标签: c++ gcc unordered-map reinterpret-cast


【解决方案1】:

不,那是不是好的做法。您的代码不安全。事实上恰恰相反:未定义的行为,这意味着有时它会起作用,有时它不会,即使没有告诉你。

真正的问题是您没有“合法”的方式将std::string 转换为struct a。这不是 C,不要使用纯字节的东西,使用语言的类型系统。然后编译器会帮助你避免严重的错误。

这是我的解决方案:

#include <unordered_map>
#include <string>
#include <iostream>
#include <algorithm>

struct a {
    std::string b;
    a () = default;
    a (const std::string& b) : b(b){}
};

int main() {
    std::unordered_map<std::string, std::string> source;
    source["1"] = "Test";
    source["2"] = "Test2";

    std::unordered_map<std::string, a> dest;

    std::transform(source.cbegin(),source.cend(),std::inserter(dest,dest.end()),[](const auto& value)
    {
        return std::forward_as_tuple(value.first,value.second);
    });

    std::cout << dest["1"].b << std::endl;
    std::cout << dest["2"].b << std::endl;
}

如果您有性能问题,您还可以添加移动构造函数等,但相信我,可读的干净代码是快速代码。不然盗版脖子不是那个非铸造代码,而是使用地图,复制而不是移动和其他东西。但不要过早优化。

【讨论】:

  • 精彩的答案! “了解(并使用)你的 stl。”应该永远是你的口头禅。但是,请指出非常糟糕的命名做法 struct a 与非类型成员 b 只是要求不可读。
  • @iolo 非常感谢,但我假设(或希望)struct a 只是为了示范而存在。
猜你喜欢
  • 2021-11-23
  • 2013-04-22
  • 2011-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-18
  • 2015-03-04
相关资源
最近更新 更多