C ++ 11 — Каков наилучший способ предотвратить неявное преобразование целого числа 0 в указатель в переполнении стека

Я пытаюсь найти лучший способ предотвратить неявное приведение целого числа 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
}

Есть ли лучший способ, чем этот? Кроме того, что именно здесь выполняет удаление?

4

Решение

Удаление 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;
}

Здесь все закомментированные вызовы конструктора не компилируются.

2

Другие решения

Если вы хотите остановить ваш конструктор от принятия 0один вариант будет удалить B(int):

B(int) = delete;

Это однозначно лучше подходит для B(0) чем конструктор, который принимает char *,

Обратите внимание, что до C ++ 11, NULL был задан как целочисленный тип, и даже в C ++ 11 и более поздних версиях он все еще, вероятно, реализован как #define NULL 0, B(NULL) не сработает, если вы это сделаете. B(nullptr) будет работать, но все же, я бы опасался, стоит ли это делать.

1

По вопросам рекламы [email protected]