I was looking for a method to initialize a static float inside a structure BUT using the constructor of the struct. In this site there are already solution to initialize the value but I was unable to find a solution that explicitly use the constructor.
The idea is the following:
struct test {
static const float a;
int b;
test(int bb, float a);
};
test::test(int bb, float aa) {
b=bb;
a=aa;
}
int main() {
int bval=2;
float aval=0.25;
struct test aaa(bval, aval);
return 0;
}
How to implement it correctly? Thank you for any advice.
You can't initialise it other than
const float test::a = something;
Outside the class (in a single compilation unit). However, you can do what you wrote and that will set the variable to the value you pass.
If you're wanting to set it only on the first time the constructor is entered, you can (but shouldn't) do something like
test::test(int bb, float aa){
static float _unused = (test::a = aa);
b=bb;
}
But that doesn't initialise it, it just assigns a value to it, and you'll still have to pass the variable to the constructor every time and nothing will be done with it (unless you give it a default value or something). That is a really terrible design though, it's probably better just to have a static function in the class to set the variable.
Static members are not associated with a particular instance, so they will only ever be initialised once. Constructors on the other hand are invoked on a per-instance basis, so it doesn't make sense to do what you're trying to do.
You can, on the other hand, assign a new value to static members in a constructor, as you're doing above, but you still have to actually initialise the static member outside the struct in the normal manner beforehand.
It's worth observing in passing that other languages (e.g. Java) have the concept of a static constructor for exactly this sort of thing - but C++ doesn't.
That said, you might find the following question interesting:
static constructors in C++? I need to initialize private static objects
You can't initialize a static const var inside constructor.
You should initialize at declaration
static const float a = 3.1416f;
Ensure you understand const keyword.
And should be integral.
Related
to avoid complicated linker rules, C++ requires that every object has
a unique definition. That rule would be broken if C++ allowed in-class
definition of entities that needed to be stored in memory as objects.
I'm having hard time understanding this:
class Y {
const int c3 = 7; // error: not static
static int c4 = 7; // error: not const
static const float c5 = 7; // error: not integral
static const int c6 = 7;
};
How does const int c6 = 7; break following rule?
C++ requires that every object has
a unique definition.
And static const int c6 = 7; do not break it (enums too)?
Please also explain why static const float c5 = 7; is not allowed but static const int c5 = 7; is allowed?
A lot of these rules have been changing over time, so it really depends on the version of C++ you are using. Also, some of these may not be technically impossible, but the committee simply decided against them because they might be hard to implement, or are prone to errors. So you might not always get the most satisfying answer on why thing are the way they are.
Lets go over them one by one.
Const Member
class Foo
{
const int bar = 7;
};
This used to be illegal before C++11. Before that version you were only allowed to initialize static variables in their declaration. If you are still not on C++11, my condolences. More details can be found here.
Static Member
class Foo
{
static int bar = 7;
};
Another one that changed, but more recently. Before C++17 it was illegal to initialize non const static variables in their declaration. This has to do with the one definition rule. When the header containing this class is included in multiple translation units (.cpp files), which one should be responsible for initializing the value? This is why you have to place the definition somewhere in a single .cpp file.
After C++17 you are allowed to do this:
class Foo
{
inline static int bar = 7;
};
When you use inline like this it somehow figures out how to only initialize it once. More details can be found here.
Static Const Float Member
class Foo
{
static const float bar = 7.0f;
};
This has mainly to do with the unpredictability of floats when you run into floating point errors. An example:
class Foo
{
static const float bar = 0.1f;
};
Since 0.1f is impossible to represent in most floating point implementations, you won't get exactly 0.1f, but only something very close to it. This can then result in different behaviors on different systems that have slightly different implementations, causing your program to run differently depending on the system.
This gets even worse when the value is the result of a calculation, because (a*b)*c is not guaranteed to be the exact same value as a*(b*c), even though it might seem like they are.
But const static floats are still allowed when you define the value outside of the class, so technically it would all still be possible to implement. But the committee never did, probably because it would cause more problems than it would solve. This is also similar to why you are allowed to use integral types as template parameters, but not floats.
template <int i> class Foo {}; // Good
template <float f> class Bar {}; // Bad
However, the committee seems to have changed it's opinion somewhat, since we are now allowed to use floats with constexpr. So it can be done if you write this instead:
class Foo
{
static constexpr float bar = 7.0f;
};
Conclusion
All of these are actually possible in some form with the right version of C++ and the right syntax. Just keep in mind the potential issues described above, and you should be good to go.
Let go through it.
FIRST READ BELOW THEN COME TO CODE
class Y {
const int c3 = 7; // It's fine. If you write good constructor.
// static int c4 = 7; // error: not const as it is trying to initialize with object constructor which it shouldn't
static const float c5 = 7; // error: not integral as we can do it for integral type only. To correct this you can do.
static constexpr float c5 = 7; // we should use constexpr for literal type.
static const int c6 = 7; // it was fine as both types are same int and 6 where it was not the case in 1st case.
};
int main()
{
Y y;
}
First, learn these lines
a. When we create a const object of a class type, the object does not
assume its constness until after the constructor completes the object's initialization.
Thus, constructors can write to const objects during their construction.
So this will yield an error.
class Const {
public:
Const(int ii);
private:
int i;
const int ci;
};
ConstRef::ConstRef(int ii)
{ // assignments:
i = ii; // ok
ci = ii; // error: cannot assign to a const
}
**TO CORRECT THIS YOU SOULD DO**
Const::Const(int ii): i(ii), ci(ii) { } // this is how constructor should be
Let's discuss everything one by one.
Your fist member is already excellent. It should work fine as per my knowledge, and it's working for me. I think it's not working for you because your constructor is trying to initialize it in the constructor body, which you can't.
We must use the constructor initializer list to provide values for members that
are const, reference, or of a class type that does not have a default
constructor.
Let come to the static part
We say a member is associated with the class by adding the keyword static to its declaration.
The static members of a class exist outside any object.
static member functions are not bound to any object; they do not have
a this pointer. As a result, static member* functions* may not be declared as const, and we may not refer to this in the body of a static member. This restriction applies both to explicit uses of this and to implicit uses of this by calling
a nonstatic member.
IMP
Because static data members are not part of individual objects of the class type, they are not defined when we create objects of the class. As a result, they are not initialized by the class’ constructors. Moreover, in general, we may not initialize a static member inside the class.
So i think you got your second error reason. You are trying to initialize it with object constructor.
Let's go to the third one.
Ordinarily, class static members may not be initialized in the class body. However, we can provide in-class initializers for static members that have const integral
type and must do so for static members that are constexprs of literal type. The initializers must be constant expressions.
So.
static constexpr float c = 7; this is fine. You can check
I hope it' clear now. Let m know if you still got issues. Btw i skipped indirect concept too. But for depth understanding you need to learn about ``literal class`.
I have class like this:
class result{
public:
int a;
int b;
int c;
};
a,b,c can be filled with any integer. However, there is some famous cases which I will use them too much like for example the zero case where (a=b=c=0) or the identity case where (a=b=c=1) and some others.
So I want an easy way to get this instances when I want one of them without creating new object and filling it manually (the real case contains much more complex that 3 integers).
What I am doing currently is like this:
class result{
public:
int a;
int b;
int c;
static result get_zero(){
return result{0,0,0};
}
static result get_idenity(){
return result{1,1,1};
}
};
and in main:
auto id=result::get_identity();
Is this a good way to achieve what I want? Is there like an idiomatic way for doing this?
If the objects can be modified after you return them, then yes, this is the correct way, since you cannot share a single object.
NRVO (http://en.cppreference.com/w/cpp/language/copy_elision) and move-semantics remove any cost associated with returning the object by value.
If you know these objects will never be changed, you can return a result const & instead and have the object itself be a static member of your class. At that point, you don't even technically need the getter/setter, since the static members are public and already marked as const.
class result{
public:
int a;
int b;
int c;
static result const zero_result{0,0,0};
static result const & get_zero(){
return result::zero_result;
}
static result const identity_result{1,1,1};
static result const & get_idenity(){
return result::identity_result;
}
};
don't forget to allocate the memory for your static data members in a .cpp file, though:
result const result::zero_result;
result const result::identity_result;
Conventionally we would probably just create a static instance that you can re-use, copy from etc.
// someFile.h
extern const result ZERO, ID;
// someFile.cpp
const result ZERO{0, 0, 0};
const result ID{1,1,1};
Alternatively, have your class own these instances as static members and have your functions return a reference.
To be honest, though, your current approach seems perfectly performant and may be the most easy-to-use.
Your proposal solution it's strongly compiler optimization efficiency. Actually when result::get_identity(); is called a new result object is created and returned.
This will invoke the initialization constructor and, in the best case, the move constructor then.
Probably your compiler will optimize that with RVO.
One good approach it may be to create const static objects from your code can refer to.
For example in your class:
class Result {
// something
public:
static const Result Zero;
static const Result Identity;
};
// ... and then you can refer to it
do_something(Result::Zero);
In that way you can refer to object which will be created only once, when your program starts and avoid instantiating always a new notorious object.
you could make a static class of your result and use that. i did this for a product i made in c# and it worked perfectly
I need to instantiate many objects from a class, but each one of them needs to be aware of a certain value X that is common for every object of this class, like a global parameter. This is necessary for my constructors to work properly in my objects.
Is there a way to do that without passing the value as a constructor parameter? What I wanna do is use the same variable in all objects so I don't waste RAM.
*in my real situation it's not just an X value, is a 1024-dimmension int vector.
What you want is a static member. "When a data member is declared as static, only one copy of the data is maintained for all objects of the class". e.g.
class myClass {
public:
static int x;
};
I assume you mean that you want a vector of size 1024 as the shared variable across all your classes. You could do this:
class MyClass {
static std::vector<int> s_my_vector;
}
This code would go into your header file. In your cpp file, you'd have to initialize the std::vector. However, I do not recommend this. Class static variables that require constructor calls (i.e. not primitives or POD types) have a lot of gotchas that I'm not planning to go into. I will offer a better solution however:
class MyClass {
static std::vector<int> & GetMyVector()
{
static std::vector<int> my_vector;
static bool initialized = MyVectorInit(my_vector);
return my_vector;
}
static bool MyVectorInit(std::vector<int> & v)
{
v.resize(1024);
...
}
public:
MyClass() {
std::vector<int> & v = GetMyVector();
...
}
static void EarlyVectorInit()
{
GetMyVector();
}
}
In this case, the static local variable ensures that there will only be one copy of my_vector, and you can get a reference to it by calling GetMyVector. Furthermore, the static bool initialized is guaranteed to only be created once, which means that MyVectorInit will only be called once. You can use this method in case you need to populate your vector in some non-trivial way that can't be done in the constructor.
The way I've written it, your vector will be created automatically the first time you need to use it, which is fairly convenient. If you want to manually trigger creation for some reason, call EarlyVectorInit().
Hi I was trying to define a constant inside a class, doing it the normal or usual way doesnt seem to work
class cat
{
public:
cat();
~cat();
private:
static const int MAX_VALUE = -99999;
int Number;
public:
void OrganizeNumbers();
void SetNumbers();
};
So the solution I found after doing some research was to declare it as static but what does this means and also I want to ask it is really necesary to declare a constant, becuase as you can see it is private right? i means it can only be accessed by the class methods so why to set a constant and also I read that using static only allows you to use integral type so its actually a dissavantage... if you are thinking to make a game.
static means that the member will be shared across all instances of your object.
If you'd like to be able to have different values of a const member in different instances you'll need to use a initialization list to set it's value inside your constructor.
See the following example:
#include <string>
struct Person {
Person (std::string const& n)
: name (n)
{
// doing: 'name = n' here is invalid
}
std::string const name;
};
int main (int argc, char *argv[]) {
Person a ("Santa Claus");
Person b ("Bunny the Rabbit");
}
Further reading
[10] Constructors - parashift.com/cpp-faq
10.1 Construct Initialization List
Initialization Lists in C++
1) Declare it "private" if you're only going to use MAX_VALUE inside your class's implementation, declare it under "public" if it's part of your class's interface.
2) Back in "C" days, "static" was used to "hide" a variable from external modules.
There's no longer any need to do this under C++.
The only reason to use "static" in C++ is to make the member class-wide (instead of per-object instance). That's not the case here - you don't need "static".
3) The "const" should be sufficient for you.
4) An (older-fashioned) alternative is to define a C++ enum (instead of a "const int")
There seems to be some confusion of ideas here:
A static member doesn't have to be an integral type, the disadvantage you mention does not exist.
const and private are unrelated, just because a member can only be accessed from instances of a given class, doesn't mean that nothing is going to change it.
Being const-correct guards against runtime errors that may be caused by a value changing unexpectedly.
you have to init the const attribute in the constructor with :
cat() : MAX_VALUE(-99999) {}
(which was declare as const int MAX_VALUE;)
I have some values such as width, height among some other that I set in the constructor at this moment. They are not currently constants but I want them to be that so I will change them now.
But I heard that it is not common to make such variables private const without also doing private static const. Is this the case? Or is it valid in this case? I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I make them constants?
Are these values specific to the instance of the object, but only set in the constructor? Then static does not make sense, as every object would have the same height and width.
If you make a private data member const, the default assignment operator won't work and you will need to provide one.
But I heard that it is not common to make such variables private const without also doing private static const.
That's a useless generalisation.
Will the values differ between instances?
Yes: make them instance members;
No: make them static members.
That's all there is to it!
I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I make them constants?
Yes, but consider doing this with an accessor function instead.
double T::centerWidth() {
return this->width / 2;
}
I have some values such as width, height among some other that I set in the constructor at this >moment. They are not currently constants but I want them to be that so I will change them now.
But I heard that it is not common to make such variables private const without also doing private >static const. Is this the case?
So, the way I would do this usually if you actually want them to be constant is as follows:
// Header
class Widget
{
public:
Widget();
~Widget();
// rest of your functions/variables
private:
static const int width;
static const int height;
// rest of your functions/variables
}
// Implementation
const int Widget::width = 640;
const int Widget::height = 800;
Widget::Widget()
{
// do some construction work
}
// ... rest of your definitions
Or is it valid in this case?
It's valid if the members you declare static will be the same for each object instance of the class you create.
I also need centerWidth, which will be set by dividing the width variable by 2. Can I do this if I >make them constants?
Yes, you can use a variable declared const in operations as normal:
const int a = 2;
int b = 2;
int c = a + b; // 4
If you are not going to change these variables by member functions then you do should declare them const and initialize in constructor initialization list.
class A
{
public:
A(int w) : width(w)
{
}
private:
const int width;
};
int main()
{
A(10);
return 0;
}
Since you set your variables in the constructor, they are instance specific, so static does not make any sense.
I know what problem you are trying to solve. You are trying to provide users read-only access to the width and height of an image, while allowing modifications from the class. You can not do that by declaring member variables const. All modification, including copy construction and assignment needs them to be non-const.
One solution is to use a public getter and a protected/private setter. In my own class I use the public member functions called xs() and ys() to return xsize and ysize respectively.
DO NOT EVEN THINK about declaring variables public const and using const_cast tricks to copy and assign, unless you like subtle, deep, pervasive bugs arising from improper compiler optimization and undefined behavior of const_cast.