簡體   English   中英

在C ++中,在成員函數中定義靜態常量變量有什么好處?

[英]In C++, what is the benefit of defining a Static Const variable within a member function?

我正在使用一個其構造函數在實現中聲明並初始化靜態const變量的類。 這不是該類的數據成員。 我了解在這種情況下使用const,但是使用static有什么好處呢?

我知道該類的所有實例都共享靜態const全局常量。 構造函數內部的變量也會發生這種情況嗎?

另外,為什么不像其他兩個那樣在Global范圍內對此進行定義? 那就是我通常定義常量的地方。

示例代碼

#includes...

static const int GLOBAL_CONST1 = 100;
static const double GLOBAL_CONST2 = 1.0;

SomeClass::SomeClass()
   :
      theDataMember1        (),
      theDataMember2        (),
      ...
{

   static const double SOME_VAR = 0.01; // Why not declare this globally?
   theDataMember1 = SomeIncludedClass(SOME_VAR);

}

無論調用該函數多少次,靜態變量都只會構造一次。

因此,如果您在函數內部定義常量並且多次調用該函數,那么為減少每次調用該函數時構造此對象的開銷,您可以將其設為靜態變量 (主要是在使用常量時,否則可能最終更改此值,很快就會搞砸了)。

對於第二個問題,這是因為您不希望其他人能夠訪問變量“ SOME_VAR”的值 提供全球范圍意味着任何人都可以訪問它。

鏈接提供了一個很好的示例,說明局部靜態有時比全局靜態變量有用的情況。

這看起來像是過早優化的嘗試。 據說創建代碼的人相信,通過使用static double變量,他們將在每次輸入函數時節省創建變量的時間。

但是,由於編譯器不是白痴,實際上這並不重要。 優化的編譯器將使用對預分配和初始化內存的訪問來替換變量,無論是static還是no static

當僅在一個函數中使用常量時,僅在使用該函數的范圍內聲明該常量才有意義。為什么在這里使用static對我來說並沒有什么意義,因為在無論如何,該類的所有實例都是編譯時間常數。

但是:您還可以根據運行時計算出的參數來初始化常量。 在這種情況下,常量的值將由該類的第一個實例定義:

class A {
public:
    A(int param)
    {
        static const int MY_CONST = param;
        cerr << "param: " << param << "  const: " << MY_CONST << endl;
    };
};

int main()
{
    A a1(1);
    A a2(2);
    return 0;
}

輸出:

param: 1  const: 1
param: 2  const: 1

//為什么不全局聲明?

通過僅看到節略的代碼片段,我們只能猜測。 通常最好將變量放在盡可能小的范圍內。 畢竟,一切都可能是全球性的-我們只是選擇封裝事物。

也許全局常量實際上在很多地方都使用過,而局部常量僅在該局部函數中使用。

但是使用靜態有什么好處呢?

可能只是一致性。 如果您只是習慣於輸入常量值,例如:

static const T val = ddd;

在任何地方,為什么要在本地進行更改? 創建常數沒有static的優點或缺點。

static變量實際上是靜態的:它們與全局變量分配在同一位置。 每次在堆棧上調用函數時,都會分配普通的局部變量。 如果函數被n次遞歸調用,則存在n個局部變量。 靜態變量僅初始化一次。 初始化后,只有一個靜態變量實例。 因此,出於性能原因,使用了static const局部變量。

變量應具有盡可能小的范圍,以避免不必要的耦合。 這就是為什么此變量是局部變量。

根據操作規范:

#includes...

static const int GLOBAL_CONST1 = 100;
static const double GLOBAL_CONST2 = 1.0;

SomeClass::SomeClass()
   :
      theDataMember1        (),
      theDataMember2        (),
      ...
{

   static const double SOME_VAR = 0.01; // Why not declare this globally?
   theDataMember1 = SomeIncludedClass(SOME_VAR);

}

必須考慮以下幾點:

  • 數據存儲單元-存儲類別說明符
  • 數據存儲持續時間-數據的最小壽命
  • 范圍可見性-數據單元可見的位置。

這是節選:

全局對象和名稱空間范圍內的對象,類的靜態數據成員以及函數中的局部靜態對象駐留在靜態存儲持續時間中。 具有靜態存儲持續時間的對象在程序執行期間始終位於相同的內存地址中。 在程序的生存期內,每個此類對象僅構造一次。 默認情況下,靜態數據被初始化為二進制零。 具有非平凡構造函數或顯式動態初始化程序的靜態對象將經歷第二個初始化階段,稱為動態初始化。

在函數中聲明為靜態的對象的范圍僅限於該函數。 具有靜態存儲持續時間的對象出現在以下示例中:

int num=0; //global variables have static storage
extern int x; //also global, defined in a separate translation unit
int func()
{
  static int calls; //local static. initialized to 0 by default
  x=calls;
  return ++calls;
}

class C
{
private:
  static bool b;
};

namespace NS
{
  std::string str; //str has static storage
}

外部存儲類說明符

extern說明符只能應用於對象名稱和函數。 extern說明符不能用於類成員或函數參數的聲明中。 聲明為extern的標識符具有外部鏈接,這意味着它們在同一程序的所有翻譯單元中均可見。

在沒有存儲類說明符的命名空間范圍中聲明的名稱具有外部鏈接,除非由於先前的聲明而具有內部鏈接且未聲明為const則具有內部鏈接。 聲明為const且未明確聲明為extern的對象具有內部鏈接,這意味着它們僅在聲明它們的翻譯單元中可見。

請注意,extern關鍵字已重載。 它也可以用於模板的顯式實例以及鏈接規范中,但是在這種情況下它不是存儲類說明符。

thread_local存儲持續時間

thread_local說明符指示命名的對象或引用具有線程存儲持續時間。 thread_local僅應應用於對象名稱或名稱空間范圍的引用以及也將靜態指定為其存儲類的對象名稱或塊范圍的引用。 thread_local存儲類是C ++ 09的新功能。 在這里詳細討論。

可以在此站點上找到: C ++參考指南| 靜態存儲期限

OP對此表示要求:

我正在使用一個其構造函數在實現中聲明並初始化靜態const變量的類。 這不是該類的數據成員。 我了解在這種情況下使用const,但是使用static有什么好處呢?

我知道該類的所有實例都共享靜態const全局常量。 構造函數內部的變量也會發生這種情況嗎?

另外,為什么不像其他兩個那樣在Global范圍內對此進行定義? 那就是我通常定義常量的地方。

根據上面的摘錄和我的直覺回答他/她的問題:

  • 他們的第一個問題: “使用靜態有什么好處?” 靜態數據存儲單元具有自動初始化。 它們僅創建一次,並駐留在同一內存地址或分配單元中。
  • 他們的第二個問題: “構造函數中的變量也會發生這種情況嗎?” 是&否-是的,在靜態存儲存儲單元中,只有在構造和初始化時才存在此變量的單個實例,但是對於類的每個實例而言,並非如此; 由於作用域可見性,它僅在此類的構造方法中是本地的。
  • 他們的最后一個問題: “而且,為什么不像其他兩個那樣在全局范圍內對此進行定義?” 根據使用目的,此特定變量可能僅在另一個對象的初始化中使用。 這樣做的好處之一可能是不必使用堆棧變量,並且僅對此類的構造函數可見。 因此,當將此構造函數稱為ctor將創建此static const variable ,並且每次構造僅初始化一次,並且一旦此類對象的構造函數超出范圍,則此static const variable將不再對任何其他函數或此類的成員或任何其他成員可見超出此范圍范圍的翻譯單位。

沒有明確的答案,但是我嘗試就OP的問題提供盡可能多的見解,並盡我所能回答這些問題。 可能有所不同的是程序員的意圖以及在其中聲明,定義,初始化然后使用這些內存分配單元的上下文。

暫無
暫無

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

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