我在头文件中有一个函数库,它包含以下函数:
// Get a normally distributed float value in the range [0,1].
inline float GetNormDistrFloat()
{
std::random_device _RandomDevice;
std::normal_distribution<float> _NormalDistr(0.5, 2.0);
float val = -1;
do { val = _NormalDistr(_RandomDevice); } while(val < 0.0f || val > 1.0f);
return val;
}
这很有效,但是,每次调用此函数std::random_device
时,我都不想创建std::normal_distribution
和GetNormDistrFloat()
个对象。
C ++中处理这个问题的“最佳”(正确)方法是什么?我试图将这两个对象定义移到函数外部,但这导致了链接器错误。我是否必须为此标头创建.cpp文件并在那里初始化对象?
答案 0 :(得分:6)
你可以将它们标记为静态变量,这使得它们的行为几乎像全局变量,但只能在函数内部访问:
void bar() {
static Foo foo_instance;
// Foo gets initialized only once
}
主要区别在于初始化。 Globals在启动时初始化,并在首次访问时初始化静态变量。
您也可以将它们设为全局变量,只需确保不在头文件中定义它们,而是将它们声明为外部:
// Header file
extern Foo foo_instance;
// Cpp file
Foo foo_instance;
本地静态对象的初始化是线程安全的,但其他一切都不是。
答案 1 :(得分:2)
我不是这里提到的其他解决方案的粉丝;例如使用全局变量或静态局部变量。首先,函数中的状态不是一个好主意,因为它在读代码时是隐含的而不是显而易见的。如果要从多个线程使用该函数,它也会使事情变得更复杂。而且它也使测试更加复杂。相反,&#34;正确&#34;处理状态的方法是做无聊的事情并创建一个类:
Sub CopyRowsWithNumbersInB()
Dim X As Long
Dim LastRow As Long
Dim Source As Worksheet
Dim Destination As Worksheet
Dim RowsWithNumbers As Range
Set Source = Worksheets("Sheet1")
Set Destination = Worksheets("Sheet2")
With Source
LastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
For X = 1 To LastRow
If _
(IsNumeric(.Cells(X, "C").Value) And .Cells(X, "C").Value < "2530" And IsNumeric(.Cells(X, "O").Value) And .Cells(X, "O").Value > "0") Or ( _
IsNumeric(.Cells(X, "D").Value) And .Cells(X, "D").Value < "2530" And IsNumeric(.Cells(X, "P").Value) And .Cells(X, "P").Value > "0") Or ( _
IsNumeric(.Cells(X, "E").Value) And .Cells(X, "E").Value < "2530" And IsNumeric(.Cells(X, "Q").Value) And .Cells(X, "Q").Value > "0") Or ( _
IsNumeric(.Cells(X, "F").Value) And .Cells(X, "F").Value < "2530" And IsNumeric(.Cells(X, "R").Value) And .Cells(X, "R").Value > "0") Or ( _
IsNumeric(.Cells(X, "G").Value) And .Cells(X, "G").Value < "2530" And IsNumeric(.Cells(X, "S").Value) And .Cells(X, "S").Value > "0") Or ( _
IsNumeric(.Cells(X, "H").Value) And .Cells(X, "H").Value < "2530" And IsNumeric(.Cells(X, "T").Value) And .Cells(X, "T").Value > "0") Or ( _
IsNumeric(.Cells(X, "I").Value) And .Cells(X, "I").Value < "2530" And IsNumeric(.Cells(X, "U").Value) And .Cells(X, "U").Value > "0") Or ( _
IsNumeric(.Cells(X, "J").Value) And .Cells(X, "J").Value < "2530" And IsNumeric(.Cells(X, "V").Value) And .Cells(X, "V").Value > "0") Or ( _
IsNumeric(.Cells(X, "K").Value) And .Cells(X, "K").Value < "2530" And IsNumeric(.Cells(X, "W").Value) And .Cells(X, "W").Value > "0") Or ( _
IsNumeric(.Cells(X, "L").Value) And .Cells(X, "L").Value < "2530" And IsNumeric(.Cells(X, "X").Value) And .Cells(X, "X").Value > "0") Or ( _
IsNumeric(.Cells(X, "M").Value) And .Cells(X, "M").Value < "2530" And IsNumeric(.Cells(X, "Y").Value) And .Cells(X, "Y").Value > "0") Or ( _
IsNumeric(.Cells(X, "N").Value) And .Cells(X, "N").Value < "2530" And IsNumeric(.Cells(X, "Z").Value) And .Cells(X, "Z").Value > "0") Then
If RowsWithNumbers Is Nothing Then
Set RowsWithNumbers = .Cells(X, "C")
Else
Set RowsWithNumbers = Union(RowsWithNumbers, .Cells(X, "C"))
End If
End If
Next
If Not RowsWithNumbers Is Nothing Then
RowsWithNumbers.EntireRow.Copy Destination.Range("A1")
End If
End With
End Sub
至少如果你编写这个类,你可以正确地测试它,或者在多个线程中使用它。您只需初始化此类一次,然后您可以重复生成浮点数。如果你真的想要方便的话,你可以这样做:
class NormDistrFloatGenerator
{
public:
NormDistFloatGenerator(const std::random_device& device,
const std::normal_distribution<float>& normal)
: m_device(device)
, m_normal(normal)
{}
float get_float() { // use member variables with same logic as in question }
private:
std::random_device m_device;
std::normal_distribution<float> m_normal;
};
然后,您可以在任何地方使用NormDistFloatGenerator& void makeGlobalFloatGenerator() {
static NormDistFloatGenerator(std::random_device, std::normal_distribution<float>(0.5, 2.0);
}
// at namespace scope
auto& g_float_generator = makeGlobalFloatGenerator();
。我真的鼓励你避免这种做法。甚至更多的是避免其他人提出的捷径。