В своем коде я только что заметил, что мне довольно часто нужно проверять наличие nullptr, хотя nullptr не должно быть возможным (в соответствии с указанными требованиями).
Однако, nullptr может все же возникнуть, поскольку другие люди могут отправлятьnullptr полагает, что это нормально (к сожалению, не все читают / записывают спецификации), и этот дефект не может быть обнаружен, если проблема не будет вызвана во время выполнения во время тестирования (и высокий охват тестированием стоит дорого).Таким образом, это может привести к большому количеству ошибок после выпуска, о которых сообщают клиенты.
например,
class data
{
virtual void foo() = 0;
};
class data_a : public data
{
public:
virtual void foo(){}
};
class data_b : public data
{
public:
virtual void foo(){}
};
void foo(const std::shared_ptr<data>& data)
{
if(data == nullptr) // good idea to check before use, performance and forgetting check might be a problem?
return;
data->foo();
}
Обычно я просто использовал бы значения-типы и передавал по ссылке и копировал.Однако в некоторых случаях мне нужен полиморфизм, для которого требуются указатели или ссылки.
Поэтому я начал использовать следующий «полиморфизм времени компиляции».
class data_a
{
public:
void foo(){}
private:
struct implementation;
std::shared_ptr<implementation> impl_; // pimpl-idiom, cheap shallow copy
};
class data_b
{
public:
void foo(){}
private:
struct implementation;
std::shared_ptr<implementation> impl_; // pimpl-idiom, cheap shallow copy
};
class data
{
public:
data(const data_a& x) : data_(x){} // implicit conversion
data(const data_b& x) : data_(x){} // implicit conversion
void foo()
{
boost::apply(foo_visitor(), data_);
}
private:
struct foo_visitor : public boost::static_visitor<void>
{
template<typename T>
void operator()(T& x){ x.foo(); }
};
boost::variant<data_a, data_b> data_;
}
void foo(const data& data)
{
data.foo();
}
Кто-нибудь еще считает, что этохорошая идея, когда практично?Или я что-то упустил?Есть ли потенциальные проблемы с этой практикой?
РЕДАКТИРОВАТЬ:
«Проблема» с использованием ссылок заключается в том, что вы не можете переместить владельца ссылки (например, вернуть объект).
data& create_data() { data_a temp; return temp; } // ouch... cannot return temp;
Тогда проблема со ссылками на rvalue (полиморфизм работает со ссылками на rvalue?) Становится невозможной для совместного использования.
data&& create_data() { return std::move(my_data_); } // bye bye data
«Безопасный» указатель на основе shared_ptr звучит как хорошая идея, но я все же хотел бы решение, где ненулевое значение применяется во время компиляции, возможно, не возможно.