重用C ++头文件中定义的函数中的对象

时间:2017-02-27 15:04:09

标签: c++ c++11

我在头文件中有一个函数库,它包含以下函数:

// 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_distributionGetNormDistrFloat()个对象。

C ++中处理这个问题的“最佳”(正确)方法是什么?我试图将这两个对象定义移到函数外部,但这导致了链接器错误。我是否必须为此标头创建.cpp文件并在那里初始化对象?

2 个答案:

答案 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(); 。我真的鼓励你避免这种做法。甚至更多的是避免其他人提出的捷径。