5

我试图找出防止整数 0 被隐式转换为 nullptr_t 然后传递给采用指针的构造函数的最佳方法。显式不这样做,但我可以让 nullptr_t 导致模棱两可的重载错误:

#include <typeinfo.h>

struct A {
    explicit A(char*) { }
};

struct B {
    B(nullptr_t a) = delete;
    B(char*) { }
};

int main(int argc, char* argv[])
{
    A a(0);         // darnit I compiled...
    B b1(0);        // good, fails, but with only b/c ambiguous
    B b2((char*)0); // good, succeeds
    B b3(1);        // good, fails, with correct error
}

还有比这更好的方法吗?另外,delete 到底在这里完成了什么?

4

2 回答 2

2

删除A(int)不会阻止A(char *)被调用 nullptr。所以你也需要删除A(nullptr_t)

即使这样也不会保护您免受邻域中有一些流氓类可以从 0 隐式构造或nullptr隐式转换为char *.

#include <iostream>

struct A {
    A(int) = delete;
    A(std::nullptr_t) = delete;
    explicit A(char * p) {
        std::cout << "Constructed with p = " << (void *)p << std::endl;
    }
};

struct X
{
    X(long i) : _i(i) {}
    operator char *() const { return (char *)_i; }
    long _i;
};

int main()
{
    X x(0);
    A a(x);
    return 0;
}

程序打印:

Constructed with p = 0

您可能认为这种可能性微乎其微,可以忽略不计;或者您可能更愿意一举删除所有构造函数,其参数并非您认可的类型。例如,假设批准的类型只是char *

struct A {
    template<typename T>
    A(T) = delete;
    explicit A(char * p) {}
};

struct X
{
    X(long i) : _i(i) {}
    operator char *() const { return (char *)_i; }
    long _i;
};

int main()
{
    // A a0(0);
    //A a1(nullptr);
    X x(0);
    // A a2(x);
    char *p = x;
    A a3(p); // OK     
    return 0;
}

这里所有被注释掉的构造函数调用都无法编译。

于 2015-10-07T19:13:39.750 回答
2

如果你想阻止你的构造函数采取0,一种选择是删除B(int)

B(int) = delete;

B(0)采用char *.

请注意,在 C++11 之前,NULL它被指定为整数类型,即使在 C++11 及更高版本中,它仍然可能实现为#define NULL 0. B(NULL)如果你这样做是行不通的。B(nullptr)会起作用,但我仍然会担心这是否值得做。

于 2015-10-08T02:03:13.300 回答