簡體   English   中英

如何處理靜態存儲持續時間警告?

[英]How to deal with static storage duration warnings?

我是一個試圖從書中學習 C++ 的新手。 下面的代碼按預期工作並產生輸出,但在定義enginerandomInt的兩行上有警告:“使用靜態存儲持續時間初始化‘引擎’可能會引發無法捕獲的異常。”

如果我將第 7 行和第 8 行放在main() ,警告會完全消失,但是enginerandomIntgetNumber不可用。

我不知道如何修復警告。 此外,也許更重要的是,除了main()之外,在各個地方使用randomInt的正確方法是什么? main()聲明它然后根據需要將它傳遞給函數是否合適? 不知何故, main()感覺不像是聲明這些類型的東西的合適地方。

我之前問過一個與此類似的問題,但我仍在努力理解,並提供了一個希望有用的示例。

// Loosely based on Fig. 6.12: fig06_12.cpp, C++ How To Program, Ninth Edition

#include <iostream>
#include <iomanip>
#include <random>

std::default_random_engine engine( static_cast<unsigned int>( time(nullptr) ) );
std::uniform_int_distribution<unsigned int> randomInt( 1, 6 );

int getNumber();

int main() {
    for ( unsigned int counter = 1; counter <= 10; ++counter ) {
        std::cout << std::setw( 10 ) << randomInt( engine );
        if ( counter % 5 == 0 )
            std::cout << std::endl;
    }
    std::cout << getNumber() << std::endl;
    return 0;
}

int getNumber () {
    return randomInt( engine );
}

輸出:

/CLionProjects/Warning/cmake-build-debug/Warning
         3         5         6         3         3
         1         4         2         4         5
2

Process finished with exit code 0

推遲全局變量初始化的一種方法是將它們包裝在get -functions中。

std::default_random_engine& getEngine()
{
   // Initialized upon first call to the function.
   static std::default_random_engine engine(static_cast<unsigned int>(time(nullptr)));
   return engine;
}

std::uniform_int_distribution<unsigned int>& getRandomInt()
{ 
   // Initialized upon first call to the function.
   static std::uniform_int_distribution<unsigned int> randomInt(1, 6);
   return randomInt;
}

然后使用getEngine()getRandomInt()而不是直接使用變量。

使用全局變量是有問題的,除非它們是絕對必要的,否則避免它們是常見的。 有關詳情,請參閱:

全球變量是否不好?

您的問題標題還涉及非全局范圍的靜態存儲持續時間變量(例如函數的靜態局部函數); 這些問題較少,但也會給您帶來一些麻煩,特別是在多線程工作中。

底線:最好只根據參數調整功能,並盡可能減少副作用。 讓我們用你的getNumber()函數做到這一點:

template <typename Distribution>
typename Distribution::result_type getNumber (
    std::default_random_engine&  random_engine,
    Distribution&                distribution) 
{
    return distribution( random_engine );
}

int main()
{
    std::default_random_engine engine( static_cast<unsigned int>( time(nullptr) ) );
    std::uniform_int_distribution<unsigned int> randomInt( 1, 6 );

    for ( unsigned int counter = 1; counter <= 10; ++counter ) {
        std::cout << std::setw( 10 ) << randomInt( engine );
        if ( counter % 5 == 0 )
            std::cout << std::endl;
    }
    std::cout << getNumber( engine, randomInt ) << std::endl;
    return 0;
}

我同意其他答案,即全局對象有問題。

但是,您的問題特別是關於可以引發異常的全局變量的初始化,反過來,沒有 C++ 范圍可以捕獲此異常(我知道)。 (此警告是clang-tidy靜態分析器中的cert-err58-cpp 。)

根據我的經驗,另一個noexcept解決方案是,如果您可以控制用作全局類的構造函數,則使構造函數調用noexcept

我認為它有一些優點:

首先,這迫使您思考是否可以避免執行可能失敗的操作(例如分配或打開文件)

struct TypeUsedAsGlobal {
    explicit TypeUsedAsGlobal(int n) noexcept {
        ... // body of the constructor that cannot fail
    } catch(...) {}
...
};

其次,如果您無法避免它們,它將迫使您處理構造函數本身中的錯誤。

struct TypeUsedAsGlobal {
    explicit TypeUsedAsGlobal(int n) noexcept try : m_{n} {
        ... // body that can fail
    } catch(...) {
        ... // handle the error
        ... // cleanup as much as you can
        ... // print a message, and most likely std::terminate
    }
...
};

(我認為try/catch范圍可以更小)。

考慮到所有因素,這還不錯,特別是如果該類型僅用於全局對象(不在范圍內),因為如果無法構造(希望)對整個程序至關重要的全局對象,您該怎么辦首先? (例如,因為文件不存在,或者如果全局對象表示的資源並不真正存在或不足以滿足程序的邏輯。)

這種方法相對於帶有static變量的函數的好處是你的程序會立即失敗,而不是在一小時后第一次使用全局對象之后。 當然,一般情況下,一種方法是否優於另一種方法尚不清楚,這取決於。


最后一點:擁有一個全局隨機數生成器是一個壞主意。 生成器應在需要或傳遞時創建。 從不同線程調用隨機數生成器/分布是不安全的,但更重要的是(數學上)原因是您必須非常小心地控制生成器的生命周期和狀態。

除了您正在使用的這本書的作者之外,沒有其他人可以指責,因為他們的不良做法而臭名昭著。

在這里查看好的替代品The Definitive C++ Book Guide and List

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM