1

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

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

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

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

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

这是可以避免的吗?

4

4 回答 4

3

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

于 2014-01-21T21:22:05.687 回答
3

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

于 2014-01-21T21:23:16.033 回答
1

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

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

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

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

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

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


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

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

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(""));
}
于 2014-01-21T21:34:59.747 回答