10

我想知道 c 或 c++ 中的静态块是什么,举个例子?我知道什么是静态的,但静态块和静态块有什么区别?

4

5 回答 5

30

另一种选择是您可能正在寻找 Java 中静态块的类比。加载应用程序时运行的代码块。C++ 中没有这样的东西,但它可以通过使用静态对象的构造函数来伪造。

foo.cpp:

struct StaticBlock {
    StaticBlock(){
        cout << "hello" << endl;
    }
}


static StaticBlock staticBlock;

void main(int, char * args[]){

}

然而。我以前被这个咬过,因为它是 C++ 标准的一个微妙的边缘案例。如果 main 调用的任何代码都无法访问静态对象,则可能会或可能不会调用静态对象的构造函数。

我发现使用 gcc hello 会得到输出,而使用 Visual Studio 则不会。

于 2010-07-30T09:17:27.747 回答
16

我在 The Code Project 上找到了这个答案。它涉及一个额外的静态变量,但我相信它比 bradgonesurfing 的答案更可靠。基本上是这样的:

class Foo
{
public:
    static int __st_init;
private:
    static int static_init(){
        /* do whatever is needed at static init time */
        return 42;
    }
};
int Foo::__st_init = Foo::static_init();

这也意味着,就像 Java 的静态块一样,您不需要实际拥有 的实例class Foo,这在类可以获取大量数据时很有用,并且您只需要在加载之前自动调用某些东西,而不是实例化它的额外实例。您可以测试该确切的代码块。我刚刚编译了它(用 static_init() 的一点输出,并让 main() 打印 Foo::__st_init,只是为了确保),它工作得很好。

$g++ -v

Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++,go --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)

编辑:

抱歉,这么晚了,但我测试了bradgonesurfing提到的内容:

如果你测试它,我在 main 中访问变量“只是为了确保”你确保变量是可访问的,因此变量将被初始化,因此 static_init 将被调用。如果你不打印 Foo::__st_init 你确定它会执行吗

我在 main.cpp 中使用了以下内容:

#include <iostream>

using namespace std;

class Foo
{
public:
    static int __st_init;
private:
    static int static_init(){
        /* do whatever is needed at static init time */
        cout << "Hello, World!";
        return 42;
    }
};
int Foo::__st_init = Foo::static_init();

int main(int argc, char** argv)
{
        return 0;
}

我编译g++ ./main.cpp -o main并运行它并收到一个友好的“Hello,World!” 我的控制台上的消息。为了彻底起见,我也编译了相同的版本,但没有打印并使用g++ ./main.cpp -g -o main. 然后我用 gdb 运行可执行文件并得到以下结果:

(gdb) break Foo::static_init
Breakpoint 1 at 0x400740: file ./main.cpp, line 12.
(gdb) start
Temporary breakpoint 2 at 0x4006d8: file ./main.cpp, line 19.
Starting program: /home/caleb/Development/test/main-c++ 

Breakpoint 1, Foo::static_init () at ./main.cpp:12
12              return 42;
(gdb) 

这是 g++ 的最新版本输出:g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2

于 2012-05-14T01:51:39.147 回答
5

C/C++ 中没有名为“静态块”的概念。然而,Java 有它,“静态块”是一个类的初始化代码块,它在创建类的第一个实例之前只运行一次。基本概念“只运行一次”可以在 C/C++ 中使用静态变量进行模拟,例如:

int some_function(int a, int b)
{
 static bool once=true; 
 if (once)
 {
  // this code path runs only once in the program's lifetime 
  once=false; 
 } 
 ...
}

然而,这不是线程安全的。在存在多个线程的情况下使其正常工作有时可能会很困难和棘手。

于 2010-07-30T09:15:34.007 回答
1

在 C++ 中有匿名命名空间的概念。

foo.cpp:

namespace {
    int x;
    int y;
}

在C中获得相同的效果

foo.cpp:

static int x;
static int y;

简单来说,当它们被声明为静态或在匿名命名空间中时,编译器不会从翻译单元中导出符号。

于 2010-07-30T09:04:31.080 回答
1

虽然 C++ 确实没有静态块作为语言的一部分,但您可以实现静态块,而您(作为用户)不必使用任何类或命名空间,并且可以编写:

#include "static_block.h" 

static_block {
     int x = 1;
     int y = 2;
     int z = x+y;
     std::cout << z << " = " << x " << " + " << y << "\n";
}

或任何你想要的。但是,您不能在类中拥有它们,仅在文件范围内。请参阅我对相关问题的回答以及static_block.h 此处的代码中对这些内容的详细描述。

注意:这不需要 C++11,并且适用于旧编译器。

于 2016-09-02T18:12:34.677 回答