【问题标题】:How do I prevent trouble arising from std::string being constructed from `0`?如何防止从 `0` 构造 std::string 引起的麻烦?
【发布时间】:2011-06-26 13:53:29
【问题描述】:
void foo (const std::string &s) {}

int main() {
  foo(0);   //compiles, but invariably causes runtime error
  return 0;
}

编译器 (g++ 4.4) 显然将0 解释为char* NULL,并通过调用string::string(const char*, const Allocator &a = Allocator()) 构造s。这当然没用,因为 NULL 指针不是指向 c 字符串的有效指针。当我尝试调用 foo(1) 时不会出现这种误解,这有助于产生编译时错误。

当我不小心调用像这样的函数时,是否有可能在编译时得到这样的错误或警告

void bar(const std::string &s, int i=1);

使用bar(0),忘记string,实际上是想拥有i=0

【问题讨论】:

  • 如果没有编译器的帮助,这并不是真的。一些实现添加了一个私有basic_string(int) 来捕获这种情况。如果没有,我猜你运气不好。
  • 我很惊讶这个通过 gcc,它以其丑陋的错误/警告而闻名,但我会在这里期待一些东西。你提高警告级别了吗?
  • @Matthieu 我找不到任何给我警告的选项,但我并不真正喜欢 gcc 警告选项。无论如何,-W -Wall -Wpointer-arith -Wcast-qual 并不能解决问题。
  • 我用clang测试过(使用gcc头文件),它也没有触发任何警告:(

标签: c++ string g++ null-pointer


【解决方案1】:

这有点难看,但你可以创建一个在实例化时会产生错误的模板:

template <typename T>
void bar(T const&)
{
    T::youHaveCalledBarWithSomethingThatIsntAStringYouIdiot();
}

void bar(std::string const& s, int i = 1)
{
    // Normal implementation
}

void bar(char const* s, int i = 1)
{
    bar(std::string(s), i);
}

然后使用它:

bar(0); // produces compile time error
bar("Hello, world!"); // fine

【讨论】:

  • +1 如果T 实际上有一个名为youHaveCalledBarWithSomethingThatIsntAStringYouIdiot 且不带参数的公共静态方法,则即使此方法失败;)
【解决方案2】:

一个有点干净的解决方法...

#include <cassert>

void foo (const std::string &s)
{
    // Your function
}

void foo(const char *s)
{
     assert(s != 0);
     foo(std::string(s));
}

【讨论】:

  • 除了这是运行时,不是编译时。
  • @robert 我知道,这只是一种可能的解决方案。
【解决方案3】:

实际上静态断言也可以。 考虑一下:

void foo (const std::string &s)
{
    // Your function
}

void foo(const char *s)
{
    #ifdef CPP_OH_X
    static_assert(s == 0, "Cannot pass 0 as an argument to foo!");
    #else
    typedef int[(s != 0) ? 1 : -1] check;
    #endif
    foo(std::string(s));
}

这里的想法是使用 static_assert,这是 C++ 中即将推出的功能,并且已经在各种编译器中实现;主要是那些支持 C++0x 的。现在,如果您不使用 C++0x,则可以使用替代方法,该方法基本上会在失败时将整数类型定义为负值。在编译时

是不允许的并且会产生错误的东西

【讨论】:

  • 这当然看起来比模板 hack 更干净,但它似乎不起作用:implctstringparam.cpp: In function ‘void foo(const char*)’: implctstringparam.cpp:9: error: ‘s’ cannot appear in a constant-expression
  • const std::string& 很可能需要是静态的才能使静态断言起作用。
  • s 的值仅在运行时知道,当函数被调用时:你不能在 static_assert 中使用它,它是在编译时评估的。 static_assert 只能计算常量表达式。
猜你喜欢
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 2014-12-03
  • 2020-03-13
  • 1970-01-01
  • 2012-03-11
相关资源
最近更新 更多