2017-02-27 50 views
2

我有一個頭文件中的函數庫,其中包括以下功能:重用對象在C++頭定義

// 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_devicestd::normal_distribution對象每次我調用這個函數GetNormDistrFloat()

什麼是C++中的「最佳」(正確)方法來處理這個問題?我試圖將這兩個對象定義移到函數之外,但這導致了鏈接器錯誤。我是否必須爲此標題創建一個.cpp文件並初始化那些對象?

+3

'_RandomDevice'是一個保留的標識符。放下主要的下劃線。 – MSalters

+0

@MSalters感謝您的反饋! – Matthias

回答

6

你可以將它們標記爲靜態變量,這使得他們的行爲就像全局,但只在函數內部訪問:

void bar() { 
    static Foo foo_instance; 
    // Foo gets initialized only once 
} 

的主要區別是初始化。全局變量在啓動時初始化,在第一次訪問時初始化靜態變量。

你也可以讓他們的全局,只是確保你沒有在頭文件中定義它們,而不是把他們定義爲外部:

// Header file 
extern Foo foo_instance; 

// Cpp file 
Foo foo_instance; 

局部靜態對象的初始化是線程安全的,但是一切不是。

+1

只是不要從多個線程調用它們。 – knivil

+1

或者添加一個互斥鎖。 – MSalters

+1

本地靜態解決方案比全局解決方案不再是線程安全的。 – molbdnilo

2

我不是這裏提到的其他解決方案的粉絲;如使用全局變量或靜態局部變量。首先,函數狀態並不是一個好主意,因爲它在讀取代碼時是隱含的而不是明顯的。如果你想使用多線程的函數,它也會使事情變得更加複雜。這也使測試更加複雜。取而代之的是,「正確」的方式來處理狀態是做無聊的事,並創建一個類:

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(); 

然後可以使用g_float_generator無處不在。我真的鼓勵你避免這種做法。而且更要避免其他人提出的捷徑。

+0

取代'device'和'normal'對象,我將採用兩個浮點數(在OP示例中爲0.5,2.0) )作爲構造函數的參數。 – Fozi

+0

@Fozi這可能是更可取的,我沒有真正強調這一點,因爲我不確定什麼是最合適的,比如說測試需求或其他。我更想強調使用一個類,因此我使用最直接映射到成員的構造函數。 –

+0

這個想法聽起來不錯,這是一個已知的隨機數發生器的反模式。通過複製狀態,可以複製數字序列,這有效地使它們非隨機。 – MSalters