Хорошо, так что иногда мой «кодирующий мозг» пропускает передачу; время от времени вы можете услышать, как переключаются передачи. (Например, время от времени я пишу class Foo : Bar {}
прежде чем напомнить себе, что это больше не правильно — и не был в долго время).
В настоящее время мой MO состоит в том, чтобы использовать встроенные методы как способ улучшить удобочитаемость и удобство сопровождения кода без ущерба для скорости, но недавно я столкнулся с проблемой, которая заставила меня усомниться в этой практике.
Итак, данный (по общему признанию) код выглядит так:
double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Magic Formula. This does what?
a = b + c - (b * c);
...
Я напишу:
double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Oh! It's probability!
a = ProbabilisticOr(b, c);
...
inline double ProbabilisticOr(double b, double c)
{
// Skip the Sanity checks
return b + c - (b * c);
}
Математика, над которой я сейчас работаю, довольно сложная. Если я хочу, чтобы общий CS / CE мог поддерживать его, он должен быть написан скорее как второй. Код также довольно чувствителен ко времени.
Я недавно столкнулся с проблемой, как я сказал выше. Я сделал мои математические константы static const double ...
как хороший маленький программист; но при попытке получить к ним доступ встроенный компилятор разорвал для DLL. Целевой ОС является Linux, но я занимаюсь разработкой для Windows (Visual Studio 2013) и хотел бы сохранить ее «кроссплатформенной безопасностью».
Решение этой маленькой проблемы это вывести их из строя; но повредит ли это моей работе? Учитывая сложную эзотерическую математику, читаемость является серьезной проблемой; но это все еще должно работать хорошо.
Обновить:
Чтобы уточнить, используя больше / другой — и гораздо более надуманный — код:
#ifndef BUILD_DLL
# define DLL_MODE __declspec(dllimport)
#else
# define DLL_MODE __declspec(dllexport)
#endifclass DLL_MODE ContrivedProbabilityExample
{
public:
inline ContrivedProbabilityExample(double value);
inline ContrivedProbabilityExample& operator+=(double value);
private:
inline void CheckValue(double value);
private:
static const double ZERO_PROB = 0.0;
static const double GUARANTEED_PROB= 1.0;
double probability;
private:
// Not implemented
ContrivedProbabilityExample();
};
inline ContrivedProbabilityExample::ContrivedProbabilityExample(double value) : probability(value)
{
CheckValue(value);
}
inline ContrivedProbabilityExample& ContrivedProbabilityExample::operator+=(double value)
{
CheckValue(value);
probability = probability + value - (probability * value);
}
inline void ContrivedProbabilityExample::CheckValue(double value)
{
if(value < ZERO_PROB || value > GUARANTEED_PROB)
throw std::range_error("Hey, whattaya think you're doing?");
}
Этот код будет отлично работать в Static на обеих платформах; это будет работать как общая библиотека в Linux. Это даст ошибку под Windows при попытке использовать его в качестве DLL. Единственное решение состоит в том, чтобы переместить CheckValue
метод вне линии.
«старая школа» inline
имел CheckValue
код метода заменяется «как есть», откуда он был вызван; по-видимому, «новая школа» встроенная … ничего? (Поскольку компилятор, очевидно, делает то, что он хочет независимо.)
AFIK Единственный способ заставить эту работу под DLL — это переместить CheckValue
out-of-line … что может быть проблемой для чувствительного ко времени кода «old-school» (каждый вызов является / гарантированно перегружен функцией). Это все еще проблема? Есть ли «лучший» способ сделать это читабельным; например не предполагать, что каждый CS / CE, работающий над моим кодом, будет опытным в области статистики?
Замечания: Это кроссплатформенный, так что «компилятор» не может быть осмысленной фразой.
Вы хотите использовать constexp
, что-то вроде:
inline constexpr double ProbabilisticOr(double b, double c)
{
// Skip the Sanity checks
return b + c - (b * c);
}
тогда вы можете делать такие вещи, как:
static const double a = ProbabilisticOr(b, c);
Не уверен, что ваш вопрос, но как насчет этого:
class DLL_MODE ContrivedProbabilityExample
{
public:
ContrivedProbabilityExample(double value)
{ CheckValue(value); }
ContrivedProbabilityExample& operator+=(double value)
{
CheckValue(value);
probability = probability + value - (probability * value);
}
private:
void CheckValue(double value)
{
if(value < ZERO_PROB || value > GUARANTEED_PROB)
throw std::range_error("Hey, whattaya think you're doing?");
}
private:
constexpr double ZERO_PROB = 0.0;
constexpr double GUARANTEED_PROB= 1.0;
double probability;
private:
// Not implemented
ContrivedProbabilityExample();
};
Если ваша проблема заключается в обеспечении производительности, лучший способ справиться с этим — вставить assert()
выполнить проверку вменяемости.
Вызывающий должен убедиться, что надлежащие значения переданы вашим функциям вероятности (и должны быть хорошо документированы), и assert()
поможет вам отладку, если какой-то вызывающий не делает. Тем не менее, когда вы отправляете свой код, вы можете просто деактивировать все утверждения, удаляя снижение производительности проверки.
Нет ничего быстрее, чем вообще не проверять, поэтому разыменование указателей в C / C ++ никогда не было безопасным и никогда не будет безопасным.