带有取消引用类型双关指针的 stof()/stoi() 将打破严格的别名规则

stof()/stoi() with dereferencing type-punned pointer will break strict-aliasing rules

我有自己的类型

namespace FaF
{
    // Allocator is my own Memory Allocator for STL
    using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
}

FaF::string number("1234");
stoi( (const std::string &) number);  <-- error

使用 stoi(number) aka FaF::string& 在 运行 gcc-Wall -Werror -Wextra 开关时导致此错误:

error: dereferencing type-punned pointer will break strict-aliasing rules [-Werror=strict-aliasing]

我尝试了很多转换,但没有任何帮助。或多或少 std::stringFaF::string 来自内存分配器的相同类型 apart

我的问题:如何使用 stoi()/stof() 函数解决此问题?

Update:: 是的,当然,我可以使用 atoi( number.c_str() ) 但我想了解这里的问题。

改用c_str和atoi:

FaF::string number("1234");
int result = atoi(number.c_str()); // result == 1234

这是 sto* class 函数的不幸问题;他们 std::string 合作。即使他们不关心你使用的是什么分配器,那仍然是类型的一部分,所以它对 C++ 仍然很重要。您也不能假装使用不同分配器的 basic_stringstd::string.

直到 C++17 solves this problem (kinda),您将不得不手动处理它:

stoi({number.data(), number.size()});

您不能将字符串与 sto* 函数一起使用。如果您查看文档 (http://en.cppreference.com/w/cpp/string/basic_string/stol),您会发现该函数的签名恰好采用 std::string。其中

std::string = std::basic_string<char, class Traits = std::char_traits<CharT>, 
    class Allocator = std::allocator<CharT>>

我想提请您注意它使用标准分配器。所以实际上你的字符串与 std::string.

不同

作为解决方法,您可以指定 std::string 运算符。

struct string : public std::basic_string<char, std::char_traits<char>, Allocator<char>>
{
    // will produce a copy. use const char* instead
    explicit operator std::string()
    {
        return c_str();
    }
    explicit operator const char*()
    {
        return c_str();
    }
};

用法示例:

FaF::string number( "1435151315" );
std::cout << std::stoi( static_cast< std::string >( number ) );
std::cout << std::atoi( static_cast< const char* >( number ) );

PS:不要使用 C 风格的转换! :)

希望对您有所帮助。

研究basic_string.hstd::stoi的定义后:

inline int
stoi(const string& __str, size_t* __idx = 0, int __base = 10)
{ return __gnu_cxx::__stoa<long, int>(&std::strtol, "stoi", __str.c_str(),
                    __idx, __base); }

然后很容易编写我自己的 - 更通用 - 版本:

namespace FaF
{
  template<typename T>
  inline int
  stoi(const T& __str, size_t* __idx = 0, int __base = 10)
  { return __gnu_cxx::__stoa<long, int>(&std::strtol, "stoi", __str.c_str(),
                    __idx, __base); }
}

这个测试脚本

FaF::string numberFaF( "1234" );
std::string numberStd( "4321" );
printf( "stoi<FaF::string>=%d - stoi<std::string>=%d\n", 
              FaF::stoi( numberFaF ), FaF::stoi( numberStd ) );

编译并产生预期结果:

stoi<FaF::string>=1234 - stoi<std::string>=4321

我只是想知道为什么还没有通用版本。 STL 中的几乎所有内容都是作为模板实现的,这个简单的函数是 硬编码std::string...