我认为既然变量是只读的,它们可以被声明为公共静态常量,这样我就可以在类外部设置它们一次。但再次强调,这似乎仍是一种丑陋的hack方法。
如果我不想在实例构造函数中初始化它们,那么有可能创建一个私有静态数据成员吗?
哇,我不敢相信没有人提到最明显的答案,也是最接近 C# 静态构造函数行为的答案,即在创建该类型的第一个对象之前不会调用。
std::call_once()
在 C++11 中可用;如果不能使用,可以使用静态布尔类变量和比较交换原子操作来实现。在您的构造函数中,尝试原子地将类静态标志从 false
更改为 true
,如果成功,则可以运行静态构造代码。
为了额外加分,请将其设置为三状态标志而不是布尔值,即未运行、正在运行和已完成运行。然后,该类的所有其他实例都可以自旋锁定,直到运行静态构造函数的实例完成(即发出内存屏障,然后将状态设置为“已完成运行”)。您的自旋锁应执行处理器的“暂停”指令,每次加倍等待时间直至达到阈值,等等 - 相当标准的自旋锁技术。
在没有 C++11 的情况下,此处 可以让您入门。
以下是一些伪代码以指导您。请将其放在类定义中:
enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;
在你的构造函数中添加以下内容:
while (sm_eClass == kNotRun)
{
if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
{
/* Perform static initialization here. */
atomic_thread_fence(memory_order_release);
sm_eClass = kDone;
}
}
while (sm_eClass != kDone)
atomic_pause();
template <typename Aux> class _MyClass
{
public:
static vector<char> a;
_MyClass() {
(void) _initializer; //Reference the static member to ensure that it is instantiated and its initializer is called.
}
private:
static struct _init
{
_init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
} _initializer;
};
typedef _MyClass<void> MyClass;
template <typename Aux> vector<char> _MyClass<Aux>::a;
template <typename Aux> typename _MyClass<Aux>::_init _MyClass<Aux>::_initializer;
.cpp
文件中,你可以有:void foobar() {
MyClass foo; // [1]
for (vector<char>::iterator it = MyClass::a.begin(); it < MyClass::a.end(); ++it) {
cout << *it;
}
cout << endl;
}
MyClass :: a ,因为它调用(并需要实例化)构造函数,后者又需要实例化 _initializer 。
__attribute__((constructor))
https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
在静态方法上标记此属性,它将在模块加载时运行,在main()之前运行。
刚刚解决了同样的问题。我不得不为Singleton指定单个静态成员的定义。 但是让事情变得更加复杂-我已经决定,除非我要使用它,否则我不想调用RandClass()的构造函数...这就是为什么我不想在我的代码中全局初始化singleton。此外,在我的情况下,我添加了简单的接口。
以下是最终代码:
我简化了代码并使用rand()函数及其单个种子初始化程序srand()
interface IRandClass
{
public:
virtual int GetRandom() = 0;
};
class RandClassSingleton
{
private:
class RandClass : public IRandClass
{
public:
RandClass()
{
srand(GetTickCount());
};
virtual int GetRandom(){return rand();};
};
RandClassSingleton(){};
RandClassSingleton(const RandClassSingleton&);
// static RandClass m_Instance;
// If you declare m_Instance here you need to place
// definition for this static object somewhere in your cpp code as
// RandClassSingleton::RandClass RandClassSingleton::m_Instance;
public:
static RandClass& GetInstance()
{
// Much better to instantiate m_Instance here (inside of static function).
// Instantiated only if this function is called.
static RandClass m_Instance;
return m_Instance;
};
};
main()
{
// Late binding. Calling RandClass ctor only now
IRandClass *p = &RandClassSingleton::GetInstance();
int randValue = p->GetRandom();
}
abc()
{
IRandClass *same_p = &RandClassSingleton::GetInstance();
}
#include <iostream>
#include <vector>
using namespace std;
namespace {
vector<int> vec;
struct I { I() {
vec.push_back(1);
vec.push_back(3);
vec.push_back(5);
}} i;
}
int main() {
vector<int>::const_iterator end = vec.end();
for (vector<int>::const_iterator i = vec.begin();
i != end; ++i) {
cout << *i << endl;
}
return 0;
}
我相信你不需要像目前被接受的答案(由Daniel Earwicker提供)那样复杂。这个类是多余的。在这种情况下,没有必要进行语言之争。
.hpp文件:
vector<char> const & letters();
.cpp文件:
vector<char> const & letters()
{
static vector<char> v = {'a', 'b', 'c', ...};
return v;
}
对于像这样的简单情况,将静态变量包装在静态成员函数中几乎同样好。它很简单,并且通常会被编译器优化掉。但是,这并不能解决复杂对象的初始化顺序问题。
#include <iostream>
class MyClass
{
static const char * const letters(void){
static const char * const var = "abcdefghijklmnopqrstuvwxyz";
return var;
}
public:
void show(){
std::cout << letters() << "\n";
}
};
int main(){
MyClass c;
c.show();
}
class ClassStatic{
private:
static char *str;
public:
char* get_str() { return str; }
void set_str(char *s) { str = s; }
// A nested class, which used as static constructor
static class ClassInit{
public:
ClassInit(int size){
// Static constructor definition
str = new char[size];
str = "How are you?";
}
} initializer;
};
// Static variable creation
char* ClassStatic::str;
// Static constructor call
ClassStatic::ClassInit ClassStatic::initializer(20);
int main() {
ClassStatic a;
ClassStatic b;
std::cout << "String in a: " << a.get_str() << std::endl;
std::cout << "String in b: " << b.get_str() << std::endl;
a.set_str("I am fine");
std::cout << "String in a: " << a.get_str() << std::endl;
std::cout << "String in b: " << b.get_str() << std::endl;
std::cin.ignore();
}
输出:
String in a: How are you?
String in b: How are you?
String in a: I am fine
String in b: I am fine
new
一个char数组,然后立即泄漏指针并覆盖它呢?! - Eric定义静态成员变量的方式与定义成员方法的方式类似。
foo.h
class Foo
{
public:
void bar();
private:
static int count;
};
foo.cpp
#include "foo.h"
void Foo::bar()
{
// method definition
}
int Foo::count = 0;
创建一个模板来模仿C#的行为,怎么样?
template<class T> class StaticConstructor
{
bool m_StaticsInitialised = false;
public:
typedef void (*StaticCallback)(void);
StaticConstructor(StaticCallback callback)
{
if (m_StaticsInitialised)
return;
callback();
m_StaticsInitialised = true;
}
}
template<class T> bool StaticConstructor<T>::m_StaticsInitialised;
class Test : public StaticConstructor<Test>
{
static std::vector<char> letters_;
static void _Test()
{
for (char c = 'a'; c <= 'z'; c++)
letters_.push_back(c);
}
public:
Test() : StaticConstructor<Test>(&_Test)
{
// non static stuff
};
};
I
和i
命名为更加晦涩的名称,以免在文件较低处意外使用它们。 - Jim Hunziker