我知道这是一个经常被问到的问题,但由于有很多变种,我想重新陈述它,并希望有一个反映当前状态的答案.就像是
Logger& g_logger() {
static Logger lg;
return lg;
}
Run Code Online (Sandbox Code Playgroud)
变量lg的构造函数是否保证只运行一次?
我从以前的答案中知道,在C++ 03中,这不是; 在C++ 0x草案中,这是强制执行的.但我想要一个更明确的答案
template <class T>
class Stack
{
public:
Stack(int = 10) ;
~Stack() { delete [] stackPtr ; } //<--- What does the "~" signify?
int push(const T&);
int pop(T&) ;
int isEmpty()const { return top == -1 ; }
int isFull() const { return top == size - 1 ; }
private:
int size ;
int top ;
T* stackPtr ;
} ;
Run Code Online (Sandbox Code Playgroud) 我想通过malloc方法创建一个整数数组.我希望这个数组是全局的,可以在我的程序中的任何地方使用.我把代码放在一个看起来像这样的头文件中:
static int *pieces;
Run Code Online (Sandbox Code Playgroud)
然后我有一个功能,用我想要的数字填充它.该函数位于命名空间中,命名空间在其自己的.cpp文件中实现.但是,我将头文件导入main.c并从创建数组的命名空间调用该函数,如:
pieces = malloc(sizeof(int) * 128);
Run Code Online (Sandbox Code Playgroud)
但是当我尝试访问main中的数组中的数字时(在调用创建我的数组的函数之后),它崩溃并说没有初始化那些碎片.但是在我拥有的功能中,我可以创建它并操纵它中的数字就好了.我的印象是,通过使片段成为静态变量,只要某个函数在任何地方发生变化(或设置它),那么这将影响变量在任何地方的使用.基本上我想说的是为什么片断在主体中显示未设置,即使我将它设置在我调用的函数中?
我已经在网上阅读了很多帖子和文章,但我找不到明确的答案.
我有一些具有类似用途的功能,我想要超出全局范围.其中一些需要公开,另一些应该是私有的(因为它们只是"公共"功能的辅助功能).另外,我不仅有函数,还有变量.它们只需要"私人"帮助函数,也应该是私有的.
现在有三种方式:
对我采取什么方式?结合其中一些方法的可能方法?
我想到了类似的东西:
谢谢.
我试图了解潜在的情况以及它是否可能是一个问题.
所以我有一个当前线程安全的静态函数.功能如下:
static thread_safe_func()
{
... process
}
Run Code Online (Sandbox Code Playgroud)
现在在这个函数中,我添加以下内容:
static thread_safe_func()
{
static const Class::NonThreadSafeClassName() *array[16] = {
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
}
... code continues here
}
Run Code Online (Sandbox Code Playgroud)
现在它本身是线程安全的吗?数组将在应用程序的整个生命周期内初始化一次,因此一旦函数thread_safe_func()被调用并完全运行,我希望这是线程安全的.
问题显然是在第一次调用期间可能发生的情况,在线程调用thread_safe_func()的情况下会发生什么,const数组的初始化发生,但在初始化完成之前,另一个线程正在调用thread_safe_func().
会改为:
static ClassMutex lock = ClassMutex()
static thread_safe_func()
{
lock.Lock()
static const Class::NonThreadSafeClassName() *array[16] = {
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
Class::NonThreadSafeClassName(),
}
lock.Unlock()
... code continues here
}
Run Code Online (Sandbox Code Playgroud)
是否值得并保证此代码现在是线程安全的?
在我研究在C#中构建Singleton的最佳方法的过程中,我偶然发现了以下文章,其中简要提及在C++中
"C++规范在静态变量的初始化顺序方面留下了一些模糊性."
我最终寻找到这个问题,并发现这个和这个.基本上(据我所知),C++中静态变量的初始化顺序是未定义的.好吧,我想到目前为止这么好,但后来我想了解文章后面的说法
"幸运的是,.NET Framework通过处理变量初始化来解决这种歧义."
所以我发现他们说的这个页面
类的静态字段变量初始值设定项对应于以它们出现在类声明中的文本顺序执行的赋值序列.
并举例说明
using System;
class Test
{
static void Main() {
Console.WriteLine("{0} {1}", B.Y, A.X);
}
public static int F(string s) {
Console.WriteLine(s);
return 1;
}
}
class A
{
static A() {}
public static int X = Test.F("Init A");
}
class B
{
static B() {}
public static int Y = Test.F("Init B");
}
the output must be:
Init B
Init A
1 1
Run Code Online (Sandbox Code Playgroud)
"因为静态构造函数执行时的规则(如第10.11节所定义)规定B的静态构造函数(以及因此B的静态字段初始化程序)必须在A的静态构造函数和字段初始化程序之前运行." …
我正在学习C ++,并且正在尝试使用我对其他语言进行编程的知识来理解C ++,这似乎使我很困惑。我正在研究一个基本的套接字程序,并试图找出处理套接字类创建的最佳方法,以便我可以读/写并且只能连接一次。
用我的其他语言,我将创建一个静态对象类,该类将允许我对其进行引用,如果未创建,则将创建套接字并进行连接。如果创建了它,我将其返回以供参考。
但是一个类不能是静态类(至少那是我读过的东西),所以我依靠的是我知道的下一个选项,即Singleton。
所以我最终得到了类似
class Socket{
static Socket* socket;
public:
Socket& Get()
{
if (!socket) socket = new Socket;
return *socket;
}
};
Run Code Online (Sandbox Code Playgroud)
我将在构造函数中有启动/连接的内容。但这是应该怎么做的吗?互联网上似乎有很多冲突的东西。例如,使用人员使用互斥锁,而某些人员使用模板。
哪种方式最适合套接字包装类?
在任何地方都写出如果存在具有相关静态变量的不同编译单元,则会出现问题.如果一个编译单元中存在静态变量,则应该没有问题:它们将按照它们在文件中的位置的顺序进行初始化.
但我有这个代码:
template <typename T>
class A{
public:
int _data;
T _obj;
A(int data) :_data(data){}
};
template <typename T>
class B{
public:
const static B<T> nullObj;
B(int data) :_a(new A<T>(data)){}
A<T> *_a;
};
template <typename T>
class C{
public:
const static C<T> nullObj;
C() :_a(nullObj._a){}
C(bool t) :_a(B<T>::nullObj._a){
_a->_data++; //FAILS HERE!
}
A<T> *_a;
};
template <typename T>
const B<T> B<T>::nullObj(0);
template <typename T>
const C<T> C<T>::nullObj(false);
class _B{};
class _A{ public: _A(){}; C<_B> g; }; …Run Code Online (Sandbox Code Playgroud) 我正在处理一些以我不理解的方式运行的遗留 C++ 代码。我正在使用 Microsoft 编译器,但我也尝试过使用 g++(在 Linux 上) - 相同的行为。
我有下面列出的 4 个文件。从本质上讲,它是一个记录成员列表的注册表。如果我编译所有文件并将目标文件链接到一个程序中,它会显示正确的行为:registry.memberRegistered为真:
>cl shell.cpp registry.cpp member.cpp
>shell.exe
1
Run Code Online (Sandbox Code Playgroud)
所以不知何故,member.cpp 中的代码被执行了(我不太明白,但还好)。
但是,我想要的是从 registry.cpp 和 member.cpp 构建一个静态库,并将其链接到从 shell.cpp 构建的可执行文件。但是当我这样做时,member.cpp 中的代码不会被执行并且registry.memberRegistered是假的:
>cl registry.cpp member.cpp /c
>lib registry.obj member.obj -OUT:registry.lib
>cl shell.cpp registry.lib
>shell.exe
0
Run Code Online (Sandbox Code Playgroud)
我的问题:为什么它以第一种方式工作,而不是第二种方式,有没有办法(例如编译器/链接器选项)使其与第二种方式一起工作?
class Registry {
public:
static Registry& get_registry();
bool memberRegistered;
private:
Registry() {
memberRegistered = false;
}
};
Run Code Online (Sandbox Code Playgroud)
#include "registry.h"
Registry& Registry::get_registry() {
static Registry registry;
return registry;
}
Run Code Online (Sandbox Code Playgroud)
关于Scot Meyers的"Effective C++"和第4项:非本地静态对象在使用之前可以是未初始化的(静态在这种情况下意味着"全局",具有静态生命).如果将其替换static为在返回对它的引用的函数内创建的local- 对象,则在使用之前确定该对象已初始化.
我总是有一个常量文件.我extern const int a;在.hpp文件中声明并在.cpp文件中定义它.但那么同样的事情会发生吗?a可以是未初始化的.或不?同样的规则是否适用于内置类型?
例如:
#include<iostream>
using namespace std;
class A
{
public:
A(){cout<<k<<endl;}//make some output
static int k;
};
A a;//before `k`'s definition
int A::k=666;
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
答案是否保证是666(我在 gcc8.1.0 中测试过,答案是666)或导致未定义的行为?
更重要的是,在这个例子中,对象a和定义A::k在同一个翻译单元中,如果它们在不同的单元中会发生什么,因为
不同翻译单元中静态变量的初始化是不确定顺序的
从我的角度来看,由于在同一个 TU 中初始化顺序是固定的,因此上面示例的答案应该是无限制的。
或者我有两个文件,每个文件都有一个全局初始化.一个取决于另一个.
简化示例:
file1.h:
#include <string>
extern const std::string PREFIX;
Run Code Online (Sandbox Code Playgroud)
file1.cpp:
#include "file1.h"
const std::string PREFIX = "prefix,";
Run Code Online (Sandbox Code Playgroud)
file2.cpp:
#include "file1.h"
std::string MSG = PREFIX + "body";
int main(){}
Run Code Online (Sandbox Code Playgroud)
我这样编译它们:
/usr/local/bin/g++-4.6.2 -c -Wall -g -o file1.o file1.cpp
/usr/local/bin/g++-4.6.2 -c -Wall -g -o file2.o file2.cpp
/usr/local/bin/g++-4.6.2 -Wall -g -o example file1.o file2.o
Run Code Online (Sandbox Code Playgroud)
当我运行它时,它会发生段错误.gdb跟踪:
Starting program: example
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b7ae0b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) ()
from /usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.6.2/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b7ae0b in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) …Run Code Online (Sandbox Code Playgroud)