с++, инициализация статических членов класса в .h файле
#define _STATIC_H_
...
#endif
на линковке ломается же. Не поможет.
Нужен класс со статическим полем (= поле, разделяемое между экземплярами)?
тогда его не надо занулять - оно автоматически будет нулём инициализировано.
то есть вот эта строка - лишняя:
long long int Timer::start_timer = 0;
quad ~/forumlocal/cpptest $ cat main.cpp
#include <iostream>
#include "static.h"
void foo;
void bar;
using namespace std;
int main
{
cout << NS::Timer::start_timer << endl;
foo;
bar;
return 0;
}
quad ~/forumlocal/cpptest $ cat user1.cpp
#include <iostream>
#include "static.h"
using namespace std;
void foo
{
cout << NS::Timer::get_time(200) << endl;
}
quad ~/forumlocal/cpptest $ cat user2.cpp
#include <iostream>
#include "static.h"
using namespace std;
void bar
{
cout << NS::Timer::get_time(300) << endl;
}
quad ~/forumlocal/cpptest $ cat static.h
namespace NS {
class Timer
{
public:
static long long start_timer;
static long long get_time(long long now)
{
if(start_timer==0)
{ start_timer=now; return 0; }
return now-start_timer;
}
};
};
quad ~/forumlocal/cpptest $ cat static.cpp
#include "static.h"
long long NS::Timer::start_timer =0;
quad ~/forumlocal/cpptest $ g++ main.o user1.o user2.o static.o -o main
Есть ещё выход, чтобы не создавать static.cpp с одной строчкой?

вообще, да, наверно проще выкинут эту строку, раз всё равно нулём инициализируется
если строчку выкинешь, тебе всё равно придётся создать экземпляр класса.
там же всё статик. Экземпляр же пустой будет
#ifndef _STATIC_H_
#define _STATIC_H_
...
#endif
то есть вот эта строка - лишняя:
всё равно придётся создать экземпляр класса.
но проще выкинут эту строку, раз всё равно нулём инициализируется

Нужен класс со статическим полем (= поле, разделяемое между экземплярами)?Не совсем так. Даже если твой компилятор позволяет опустить определение статического поля, инициализируемого по умолчанию, на других компиляторах это может не работать (только что проверил MSVS2012 и gcc 4.4.6, - определение необходимо).
тогда его не надо занулять - оно автоматически будет нулём инициализировано.
то есть вот эта строка - лишняя:long long int Timer::start_timer = 0;
Даже если компилятор поддерживает отсутствие определения в такой ситуации, пользоваться этим я бы не стал, потому что тогда из любого cpp-файла можно изменить поведение класса, добавив это определение с любым инициализатором. Если же определение есть, то добавление второго приведет к конфликту.
There shall be exactly one definition of a static data member that is odr-used (3.2) in a program; no diagnostic is required.
По новому стандарту можно также указать инициализатор в объявлении (в теле класса) при условии, что инициализатор - константное выражение. Это, однако, не отменяет требование наличия определения (соответственно, уже без инициализатора). Но такой синтаксис пока поддерживается, если не ошибаюсь, только g++ и clang.
если строчку выкинешь, тебе всё равно придётся создать экземпляр класса.Статические поля создаются независимо от того, создаются ли экземпляры класса. Время жизни у них такое же, как у глобальных переменных.
Static data members are initialized and destroyed exactly like non-local variables
Аналог inline это анонимный ns, но тогда будем иметь несколько экземпляров этой глобальной переменной (в каждом .o файле)
Я надеялся, что есть какой-то такой механизм:
в каждом .o файле появляется по своему экземпляру переменной, но во время линковки выбирается какой-то один. Но это скорее даже нужна поддержка не столько со стороны языка, сколько линковщика и всех архитектуры этой линковки
Есть! Но чё-то я не уверен, что он тебе понравится =)
[xoft c++]$ cat static.h
#pragma once
template<class T>
struct _C {
static int x;
};
template<class T>
int _C<T>::x = 100;
typedef _C<void> C;
[xoft c++]$ cat static1.cpp
#include "static.h"
int f {
return C::x;
}
[xoft c++]$ cat static2.cpp
#include "static.h"
#include <iostream>
using namespace std;
int f;
int g {
return C::x + 1;
}
int main {
cout << f + g << endl;
}
[xoft c++]$ g++ -c static1.cpp
[xoft c++]$ g++ -c static2.cpp
[xoft c++]$ g++ -o static static1.o static2.o
[xoft c++]$ ./static
201
А как так получается? Где хранится _C<void>::x ?
немного изменил пример, чтобы было видно, что переменная общая:
$ cat static.h
#pragma once
template<class T>
struct _C {
static int x;
};
template<class T>
int _C<T>::x = 100;
typedef _C<void> C;
$ cat static1.cpp
#include "static.h"
int f {
return ++C::x;
}
$ cat static2.cpp
#include "static.h"
#include <iostream>
using namespace std;
int f;
int g {
return ++C::x;
}
int main {
cout << f + g << endl;
}
$ g++ -c static1.cpp
$ g++ -c static2.cpp
$ g++ -o static static1.o static2.o
$ ./static
203
template<>
int C::x = 100;
Иначе можно создать еще один файл, который будет инициализировать эту переменную по-своему с помощью аналогичной строчки (причем в зависимости от компилятора и прочих факторов будет использоваться либо это определение, либо определение из static.h).
Но, имхо, все равно грязновато выглядит. Всего лишь для того, чтобы не писать cpp-файл из двух строк, пишется десяток в хедере... Понятней код от этого точно не станет.
Кстати, судя по начальному посту, реализуется счет времени. <chrono> или Boost.Chrono использовать нельзя?
#pragma onceЗакопайте стюардессу!
Всего лишь для того, чтобы не писать cpp-файл из двух строк, пишется десяток в хедере...
#define HEAVENLY_STATIC(C, int, x) \
template<class T> struct _C { \
static int x; \
}; \
\
template<class T> int _C<T>::x = 100; \
\
typedef _C<void> C
HEAVENLY_STATIC(C, int, x);

class Timer
{
public:
static long long int& start_timer
{
static long long int v = 0;
return v;
}
static long long int get_time(long long int now)
{
if(start_timer == 0)
{
start_timer = now;
return 0;
}
return now - start_timer;
}
};
Функция будет inline, а компилятор гарантирует, что во всех единицах трансляции у нее будет одна и та же статическая переменная. Собсно, это тот же синглтон, только частный случай в твоем классе.
Оставить комментарий
Phoenix
Приводит к multiple definition of `NS:Как поступать с функциями понятно, сделать их inline, тогда они с друг другом не конфликтуют.
По аналогии, можно класс и инициализацию включить в namespaece { ... }, но тогда в каждом .cpp будет юзаться свой экземпляр класса, а значит статик переменная будет не общая.
Есть ещё выход, чтобы не создавать static.cpp с одной строчкой?