在C ++中,在成员函数中定义静态Const变量有什么好处?

时间:2016-03-09 17:09:49

标签: c++

我正在使用一个类,其构造函数在实现中声明并初始化一个静态const变量。这不是该类的数据成员。我理解在这种情况下使用const,但是使用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);

}

6 个答案:

答案 0 :(得分:4)

无论调用函数多少次,

静态变量只构造一次。

因此,如果函数和函数内的定义常量被多次调用,那么每次调用函数时都会降低构造此对象的成本,这会使它成为静态变量(当它是一个常数时主要是有用的,否则你最终可能会改变这个值,很快就会搞砸了。)

对于您的第二个问题,这是因为您不希望其他人能够访问变量“SOME_VAR”的值。提供全局范围意味着任何人都可以访问它。

这个link提供了一个很好的例子,说明局部静态有时比全局静态变量有用。

答案 1 :(得分:1)

这看起来像是过早优化的尝试。据称,创建代码的人认为,通过使用static double变量,他们将在每次输入函数时保存创建变量。

然而,由于编译器不是笨蛋,实际上它根本不重要。优化编译器将替换变量,可以访问预分配和初始化的内存,无论static还是没有static

答案 2 :(得分:1)

当常量仅在一个函数中使用时,仅在它所使用的函数范围内声明它是有意义的。为什么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

答案 3 :(得分:1)

  

//为什么不全局声明?

只看到一个删节的代码片段,我们只能猜测。将变量放在尽可能最窄的范围内通常是一种好习惯。毕竟,可以是全局的 - 我们只是选择封装东西。

也许全局常量实际上在很多地方使用,而局部常量仅用于本地函数。

  

但使用静态获得了什么?

可能只是一致性。如果您只是习惯输入常量值,例如:

static const T val = ddd;

无处不在,为什么要在本地进行更改? static没有优势或劣势来创建常数。

答案 4 :(得分:0)

static变量实际上是静态的:它们被分配在与全局变量相同的位置。每次在堆栈上调用函数时都会分配普通局部变量。如果函数以递归方式调用 n 次,则存在 n 局部变量。静态变量只初始化一次。初始化之后,只有一个静态变量实例。因此,出于性能原因,使用了static const局部变量。

变量应具有尽可能窄的范围,以避免不必要的耦合。这就是为什么这个变量是本地的。

答案 5 :(得分:0)

根据OP的代码:

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

}

必须考虑以下几点:

  • 数据存储单元 - 存储类说明符
  • 数据存储持续时间 - 数据的最短生命期
  • 范围可见性 - 数据单位可见的位置。

以下是摘录:

  

命名空间作用域中的全局对象和对象,类的静态数据成员以及函数中的本地静态对象驻留静态存储持续时间。具有静态存储持续时间的对象在整个程序执行期间驻留在相同的存储器地址中。每个这样的对象在程序的生命周期中只构造一次。默认情况下,静态数据初始化为二进制零。具有非平凡构造函数或显式动态初始化程序的静态对象经历称为动态初始化的第二个初始化阶段。

     

在函数中声明为static的对象的范围仅限于该函数。具有静态存储持续时间的对象显示在以下示例中:

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说明符不能用于类成员或函数参数的声明。声明为extern的标识符具有外部链接,这意味着它们可以从同一程序的所有翻译单元中看到。

     

在没有存储类说明符的命名空间作用域中声明的名称具有外部链接,除非由于先前的声明而具有内部链接,并且未将其声明为const。声明为const且未显式声明为extern的对象具有内部链接,这意味着它们仅在声明它们的转换单元中可见。

     

请注意,extern关键字已重载。它也可以用于模板和in和linkage-specification的显式实例化,但它不是这种上下文中的存储类说明符。

     

thread_local存储持续时间

     

thread_local说明符指示命名对象或引用具有线程存储持续时间。 thread_local只应用于对象名称或命名空间作用域的引用,以及块作用域的名称或块作用域的引用,它们还将static指定为其存储类。 thread_local存储类是一个新的C ++ 09功能。这里将详细讨论。

可在此网站找到:C++ Reference Guide | Static Storage Duration

OP已经声明并问过这个问题:

  

我正在使用一个类,其构造函数在实现中声明并初始化一个静态const变量。这不是该类的数据成员。我理解在这种情况下使用const,但是使用static获得了什么?

     

我知道静态const全局常量由类的所有实例共享。构造函数中的变量也会发生这种情况吗?

     

另外,为什么不像其他两个那样在全球范围内定义?这就是我通常会定义常量的地方。

根据以上摘录和我自己的直觉回答他/她的问题:

  • 他们的第一个问题: “使用静态获得了什么?”静态数据存储单元具有自动初始化。它们只创建一次并驻留在相同的内存地址或分配单元中。
  • 他们的第二个问题: “构造函数中的变量也会发生这种情况吗?”是的&amp;否 - 是的,在静态存储内存单元中构造和初始化时,这个变量有一个实例,但是这个类的每个实例都看不到它;由于范围可见性,它仅对此类的构造函数是本地的。
  • 他们的最后一个问题: “另外,为什么不像其他两个那样在全球范围内定义?”这个取决于使用意图的特定变量可能只用于另一个对象的初始化。这样做的好处之一可能是不必使用堆栈变量,并且只对此类的构造函数可见。因此,当调用此构造函数ctor时,将创建此static const variable并且每个构造仅初始化一次,并且一旦此类对象的构造函数超出范围,此static const variable将不再由任何其他函数可见或此类的成员,或超出此范围可见性的任何其他翻译单元。

没有确定的答案,但是我试图尽可能多地提供关于OP问题的见解,并试图尽我所能地回答它们。一些可能变化的事情是程序员的意图以及这些内存分配单元的声明,定义,初始化然后使用的上下文。