How to make increment/decrement static variable for an API? - c++

#include <iostream>
class Test {
public:
static int numelem;
Test() {}
~Test() {}
int increment();
};
int Test::numelem = 0;
int Test::increment()
{
return ++Test::numelem;
}
So I want to make a counter for my Stacks data structure.
Whenever I push, it increments and when popped it decrements.
My code works, but int Test::numelem = 0; is a global variable.
I tried using inline but unfortunately I have C++14.
I only put the static int numelem instead of the whole Stack class to focus on one feature.
Is there an alternative way I can put int Test::numelem = 0; inside the class without getting any error?

This is the typical workaround. It's particularly useful for templates.
class Test {
public:
static int& numelem() {
static int val = 0; // or your initializer here
return val;
}
int increment() {
return ++numelem();
}
};
Of course, now you're accessing it with the syntax Test::numelem() instead of just Test::numelem. But something like ++Test::numelem() still works just fine.

but int Test::numelem = 0; is a global variable.
Technically, it is not a global variable but a class static member. Functionally they behave very similarly.
Is there an alternative way I can put int Test::numelem = 0; inside the class without getting any error? unfortunately I have C++14.
With C++14 the out-of-class definition for a nonconst static data member should be in the same namespace scope where the class was defined(global namespace in your example). So there is no way of defining a nonconst static data member inside the class in c++14 as we can't use inline in c++14 and the only way of defining a nonconst static data member is to put a definition at namespace scope.
This can be seen from class.static.data:
The declaration of a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member shall appear in a namespace scope enclosing the member's class definition.
But with C++17 we can use inline to define a non-const static data member inside the class.

Related

C++ singleton LNK2019 error [duplicate]

I'd like to have a class that has static members to itself, but I can't figure how to do that. Is that even possible?
I get the error:
only static const integral data members can be initialized within a class
Code:
namespace misc
{
class CData
{
public:
CData( ) { };
CData( int d );
CData& operator = ( const CData& d );
static const CData FIRST = CData( 512 ); //how?
private:
int data;
};
}
As I use FIRST a lot I would like to statically access it using misc::CData::FIRST without the need to declare it somewhere in the scope. Is that by any chance possible?
... without the need to declare it somewhere in the scope. Is that by any chance possible?
No, it's not possible without declaring it (which you already tried to do in your class declaration). You probably meant, without defining it outside your class declaration. Again the answer is no.
You have to separate declaration and definition for this case (it only works with primitive integral types like int to initialize these directly in the class declaration).
First have a simple declaration in your class declaration (usually something like CData.hpp)
namespace misc {
class CData {
public:
CData( ) { };
CData( int d );
CData& operator = ( const CData& d );
static const CData& FIRST;
private:
int data;
};
}
and then define it in a separate compilation unit (usually something like CData.cpp)
namespace misc {
const CData& CData::FIRST = CData( 512 );
}
For non-integral data, something like this is preferred since it avoids the static initialization fiasco.
static const CData FIRST()
{
static CData first(512); //only initialized once, when first requested
return first;
}
... without the need to declare it somewhere in the scope. Is that by
any chance possible?
No.
C++ Standard n3337 § 9.4.2/2
Static data members
The declaration of a static data member in its class definition is not
a definition and may be of an incomplete type other than cv-qualified
void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition. (...)
You can declare a static data member in class:
namespace misc {
class CData {
public:
//...
static const CData FIRST; // declaration
//...
}
and define it in (exactly) one of the .cpp files:
namespace misc {
CData CData::FIRST = CData( 512 ); // definition
}
This is preferred solution, however you need to have this definition out of your class. You could have defined the member in class if it was of an integral type
C++ Standard n3337 § 9.4.2/3 says
If a non-volatile const static data member is of integral or
enumeration type, its declaration in the class definition can specify
a brace-or-equal-initializer in which every initializer-clause that is
an assignment- expression is a constant expression (...)

Why is the static variable initialized with redeclaration of static variable outside the class? Can't we just initialize it instead of redeclaring it?

#include <iostream>
using namespace std;
class Box
{
public:
static int objectCount;
}
// Initialize static member of class Box
int Box::objectCount = 0;
It seems that you mix up the declaration and the definition of a variable.
The declaration just tells the compiler a name.
So in your case:
class Box
{
public:
static int objectCount;
};
This just tells the compiler that there is a variable with the name objectCount.
But now you still need a definition.
int Box::objectCount = 0;
Simplified the definition is what the linker needs.
So as a simple rule static member variables must be declared in the class and then defined outside of it.

static member variable when declared private

When a static member variable is declared private in a class, how can it be defined?
Suppose i have the following class declaration
class static_demo
{
private:
static int a;
public:
static int b;
void set(int x, int y)
{
a = x;
b = y;
}
void show()
{
cout << "a = " << a << "\n";
cout << "b = " << b << "\n";
}
};
Then the following statement to define a will result in compilation error.
int static_demo::a;
So is it possible to have a static data member in the private section of class?
Adding full code as per Greg,
#include <iostream>
using namespace std;
class static_demo
{
private:
static int a;
public:
static int b;
void set(int x, int y)
{
a = x;
b = y;
}
};
int static_demo::a;
int static_demo::b;
int main()
{
static_demo::b = 10;
static_demo::a = 20;
return 0;
}
The compilation error is:
static_member_variable.cpp: In function `int main()':
static_member_variable.cpp:20: error: `int static_demo::a' is private
static_member_variable.cpp:26: error: within this context
When a static member variable is declared private in a class, how can it be defined?
In the very same way as you define a public static variable in your source(cpp) file.
int static_demo::a = 1;
Access specifiers will not give you error while defining the member. Access specifiers control the access of the member variables, defining a static variable is an excpetion which is allowed.
Compiles cleanly on Ideone here.
EDIT: To answer your Q after you posted code.
Your problem is not the definition of the static member. The error is because you are trying to access the private static member inside main. You cannot do that.
Private members of a class can only be accessed inside the class member functions, the same rule applies even to static members. To be able to modify/access your static members you will have to add a member function to your class and then modify/access the static member inside it.
in your .cpp:
int static_demo::a(0);
when this causes an error, it is most common that you either encountered a linker error for a multiply defined symbol (e.g. the definition was in the header), or that you may have tried to define it in the wrong scope. that is, if static_demo is in the namespace MON, it would be defined in the .cpp:
#include "static_demo.hpp"
int MON::static_demo::a(0);
for other types, it may simply have been an incorrect constructor.
The problem is not the definition, but the fact that in main() (that's not in the name scope of static_demo, and cannot see a being private), you do an assignment.
The definition of a is what you did at global scope, with int static_demo::a;.
You simply need an initializer, if you want a not to start with an undefined value.
int static_demo::a = 1;
will solve the problem.
From than on, a can be manipulated only by functions in static_demo (of friend of it).

Static variable for object count in c++ classes?

I would like to have a static member variable keep track of the amount of objects that have been made. Like so:
class test{
static int count = 0;
public:
test(){
count++;
}
}
That doesn't work because, according to VC++, a member with an in-class initializer must be constant. So I looked around and apparently you're supposed to do:
test::count = 0;
Which would be great, but I want count to be private.
edit:
Oh boy, I just realized I need to do:
int test::count = 0;
I had seen something just do test::count = 0, so I assumed you wouldn't have to declare type again.
I'd like to know if there's a way to do this inside the class though.
edit2:
What I'm using:
class test{
private:
static int count;
public:
int getCount(){
return count;
}
test(){
count++;
}
}
int test::count=0;
Now it's saying: 'test' followed by 'int' is illegal (did you forget a ';'?)
edit3:
Yup, forgot a semicolon after the class definition. I'm not used to having to do that.
Put
static int count;
In your header in the class definition, and
int test::count = 0;
In the .cpp file. It will still be private (if you leave the declaration in the header in the private section of the class).
The reason you need this is because static int count is a variable declaration, but you need the definition in a single source file so that the linker knows what memory location you're referring to when you use the name test::count.
Initialization of static variable within a function is allowed so a solution can be something like this
class test
{
private:
static int & getCount ()
{
static int theCount = 0;
return theCount;
}
public:
int totalCount ()
{
return getCount ();
}
test()
{
getCount () ++;
}
};
in general using this technique it is possible to work around the C++ limitation regarding static member initialization in the declaration.
static class members must be defined (and potentially initialized) at namespace scope, member access rules do not apply.

multiple definition for static member?

Failed to link up following two files, when I remove the "static" keyword, then it is okay. Tested with g++.
Check with readelf for the object file, the static member seems is exported as a global object symbol... I think it should be a local object ...?
static1.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
static2.cpp
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
void second()
{
StaticClass statc1;
static1.setMemberA(2);
}
With error info:
/tmp/ccIdHsDm.o:(.bss+0x0): multiple
definition of `StaticClass::a'
It seems like you're trying to have local classes in each source file, with the same name. In C++ you can encapsulate local classes in an anonymous namespace:
namespace {
class StaticClass
{
public:
void setMemberA(int m) { a = m; }
int getMemberA() const { return a; }
private:
static int a;
};
int StaticClass::a = 0;
} // close namespace
void first()
{
StaticClass statc1;
static1.setMemberA(2);
}
The following is a definition of the static data member. It has to occur only in one file that's compiled and then linked.
int StaticClass::a = 0;
If you have multiple such definitions, it is as if you had multiple functions called first. They will clash and the linker will complain.
I think you are mistaking static members with static applied to namespace scope variables. At the namespace level, static gives the variable or reference internal linkage. But at the class scope level (when applied to a member), it will become a static member - one that is bound to the class instead of each object separately. That then has nothing to do with the C meaning of "static" anymore.
The statement
int StaticClass::a = 0;
actually allocates storage for the variable, this is why it should be only written once.
As for your remark, you are probably confusing two different uses of the static keyword. In C static used to mean "use internal linkage", this means that the name of a variable or function would not be seen outside the translation unit where it was defined.
In classes, static is used to define class members, that is variables or methods that don't refer to a specific instance of the class. In this case the storage for a static variable must be allocated somewhere (as it is not part of any instance), but only in one place of course.
StaticClass needs a place to store a, a static variable that will be shared by all class instances - there are two lines that do so, one in each file. Removing one will fix the linker error.