【问题标题】:C++ How to detect when nullptr is passed to function where std::string is expected?C ++如何检测何时将nullptr传递给预期std :: string的函数?
【发布时间】:2014-01-21 21:14:49
【问题描述】:

我找不到对此给出明确答案的线程 -

我有一个构造函数,例如:

FanBookPost::FanBookPost(Fan* owner, std::string content);

Fan 是我代码中的另一个类,但内容是有问题的:

因为 std::string 不是指针,我希望用 (fan, nullptr) 调用构造函数是不可能的。但是,它编译! ...并在运行时使用 EXC_BAD_ACCESS 崩溃。

这是可以避免的吗?

【问题讨论】:

  • 如果您真的想要,您可以使用const char * 版本重载它,如果不为空则转发。
  • 调用std::string构造函数时会发生崩溃,这不是您的代码的问题。
  • 你可以用一个接受std::nullptr_t的函数来重载它。非空指针常量不会选择这个重载。
  • @dyp 虽然这不会阻止char *c = 0; FanBookPost fbp(..., c);甚至FanBookPost fbp(..., 0);之类的事情。
  • @delnan 0 是一个空指针常量。

标签: c++ string nullptr


【解决方案1】:

这里的问题是当调用std::string 的构造函数时会发生崩溃(因为在那里访问了一个解释为const char* 的nullptr)。在这里你无能为力,只能告诉其他人不要做坏事。这不是你的构造函数的问题,因此不是你的责任(除了你不能阻止它)。

【讨论】:

    【解决方案2】:

    您观察到的是,您可以从字符指针(在本例中为 nullptr)隐式创建 std::string,然后将其传递给函数。但是,不允许从空指针创建 string。你的方法签名没有问题,只是客户端使用违反了std::string构造函数的约定。

    【讨论】:

      【解决方案3】:

      如果你真的想要安全的话,如何使用代理/包装器类型:

      template<typename T>
      struct e_t
      {
      public:
          inline e_t ( e_t const & other )
              : m_value( other.m_value )
          {}
      
          inline T & value( void )                { return m_value; }
          inline operator T&()                    { return m_value;   }
          inline e_t( const T& c ) : m_value( c )     {}
      
      private:
          T m_value;
      };
      
      void FanBookPost(int* owner, e_t<std::string> content) {
      }
      
      int main()
      {
          int n = 0;
          //FanBookPost(&n, 0); // compiler error
          //FanBookPost(&n, nullptr); // compiler error
          //FanBookPost(&n, ""); // unfortunately compiler error too
          FanBookPost(&n, std::string(""));
      }
      

      【讨论】:

        【解决方案4】:

        问题在于 std::string 有一个非显式 ctor,它将 char * 作为其唯一(必需)参数。这给出了从 nullptrstd::string 的隐式转换,但给出了未定义的行为,因为该 ctor 特别需要一个非空指针。

        有几种方法可以防止这种情况。可能最有效的方法是对std::string 进行(非常量)引用,这需要将(非临时)string 作为参数传递。

        FanBookPost::FanBookPost(Fan* owner, std::string &content);
        

        这确实带来了不幸的副作用,即赋予函数修改传递的字符串的能力。这也意味着(使用符合标准的编译器1)您将无法将nullptr 字符串文字传递给函数-您必须传递std::string 的实际实例。

        如果您希望能够传递字符串文字,则可以添加一个采用char const * 参数的重载,也可能添加一个采用nullptr_t 参数的重载。前者会在创建字符串并调用引用字符串的函数之前检查非空指针,后者会做一些事情,比如记录错误并无条件地终止程序(或者,可能只是记录错误并抛出异常)。

        这既烦人又不方便,但可能优于目前的情况。


        1. 不幸的是,我上次注意到 MS VC++ 在这方面不符合要求。它允许通过非常量引用传递临时对象。通常这是相当无害的(它只是让你修改临时的,但通常没有明显的副作用)。在这种情况下,它会更麻烦,因为您专门依赖它来防止传递临时对象。

        【讨论】:

        • 我建议使用/Za(禁用语言扩展)。
        猜你喜欢
        • 2021-10-27
        • 2011-04-18
        • 2017-07-10
        • 2011-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多