Initialize a struct in C++ the C way - c++

I initialize a static struct in C like that, but in C++ it doesn't want to compile. How do I get the equivalent in C++ that would still be compatible with C? (linux C code that I'm trying to compile on MSVC)
typedef struct float3 {
float x,y,z;
} float3;
void main() {
static float3 value = (float3){ 1.f, 5.f, 10.f };
}
MSVC (visual studio 2019) gives error at the opening bracket '{' after (float3).
Error (active) E0029 expected an expression cpptestvs D:\Projects\cpptestvs\cpptestvs\cpptestvs.cpp 11

Try removing the cast to float3 in the statement enclosed inside void main().

static float3 value = (float3){ 1.f, 5.f, 10.f };
This is a compound literal, which is allowed in C but not C++. C allows you to create an unnamed object of the type float3 and initialise it with an initializer-list. Some compilers, such as GCC, do support it as an extension but MSVC doesn't.
To do what you want you can do:
static float3 value = { 1.f, 5.f, 10.f };
This is aggregate initialisation: every non-static class member in the struct float3 is copy-initialized from the corresponding clause of the initializer list. Your struct is an aggregate because it has no user-declared constructors, no private or protected non-static data members, no base classes, and no virtual functions.

Related

In struct nested union/array member default initialization compiles, but is not happening correctly?

I am trying to initialize array members at struct declaration in the following struct with nested union & array:
struct Nested
{
union
{
short sArray[5] = {42};
float fVal; // Must NOT be initialized - obviously, only 1 member of a union can be
};
double dArray[5] = {77.7};
};
While the code compiles just fine, only first elements of both arrays are initialized, when running/debugging the code..
sArray[0] is set to 42, remaining elements are all set to 0
dArray[0] is set to 77.69999, remaining are all set to 0
All other answers I found, mention initialization at instance declaration, but not default init in struct/class declaration.
I have not seen/found whether this syntax is enabled (for array members too) by gnu c++17.
However, since it compiles WO warning one would assume it should correct.
Am I doing something wrong ?
Edit:
Or how do I simply initialize my arrays ?
What you are doing is aggregate initialization, which means the elements in sArray and dArray are value initialized when not specified. Because short and double are scalar types, this means zero initialization
Since you don't specify anything but the first element, all remaining elements will be initialized to 0
As requested in the comments, a way to initialize the arrays would be std::fill or std::fill_n:
#include <algorithm>
struct Nested {
explicit Nested() {
std::fill_n(sArray, 5, 0);
std::fill_n(dArray, 5, 0.0);
}
union {
short sArray[5];
float fVal; // Must NOT be initialized - obviously, only 1 member of a
// union can be
};
double dArray[5];
};
In general, I would recommend to instead use std::array and its fill function:
#include <array>
struct Nested {
explicit Nested() {
sArray.fill(0);
dArray.fill(0.0);
}
union {
std::array<short, 5> sArray;
float fVal; // Must NOT be initialized - obviously, only 1 member of a
// union can be
};
std::array<double, 5> dArray;
};

uninit_member: Non-static class member field m_cJobState.bstatus is not initialized in this constructor nor in any functions that it calls

I am getting the below warning at SubManager constructor:
Uninitialized scalar field (UNINIT_CTOR)
uninit_member: Non-static class member field m_cJobState.bEULA is not initialized in this constructor nor in any functions that it calls.
uninit_member: Non-static class member field m_cJobState.bstatus is not initialized in this constructor nor in any functions that it calls.
uninit_member: Non-static class member field m_cJobState.eActivationState is not initialized in this constructor nor in any functions that it calls.
Below is the code snippet:
SubManager.h file
struct MgrStatus
{
bool bEULA;
bool bstatus;
WorkState eActivationState;
};
class SubManager
{
private:
MgrStatus m_cJobState;
};
SubManager.cpp file
SubManager::SubManager()
{
}
To resolve the warning,
Do we need to initialize structure variables in the above constructor?
If we need to initialize, how to initialize the enum variable (WorkState eActivationState;)?
You did not specify from what tool you got warnings and also posted code
should give different errors I suspect. Seems that the tool requires you to initialize all aggregate members in constructors (C++ standard does not).
Since C++11 (question was tagged like that) it should compile and run with uniform initialization of aggregate members:
enum WorkState {SomethingElse, Crappy, Etc}; // wasn't defined in OP
struct MgrStatus
{
bool bEULA;
bool bstatus;
WorkState eActivationState;
};
class SubManager
{
public:
SubManager(); // constructor declaration was missing in OP
private:
MgrStatus m_cJobState;
};
SubManager::SubManager()
: m_cJobState{false,false,Crappy}
{ }
int main() // to demo it runs
{
SubManager s;
(void)s; // just to silence unused variable s warning
}

assigning constant value to struct members to be used in 1 class

So far I've read about structs, with and without pointers. My question is about a struct in combination with a class and main. What I learn from K&R and c++ sites is that a struct can't contain values. The values I want to assign to the members will be constants. In several posts I read that I should put the struct inside the class and even inside private. The setup I use was:
class C
{
struct something {const float m = 3} s;` //actually 12 members. Compiler doesn't accept values: "ISO C++ forbids initialization of member"
function foo(struct something s){ float m = s.m; <..do something..>}` //struct s actually used in several functions
};
int main(){C c;}
Then I created 2 structs, and letting the 2nd assign values to the members of the first, which I find ugly. But why did that get accepted by gcc? So how can I assign the values only once in a proper way since assigning values has to be done inside a function. BTW, I'm using Ubuntu gcc-4.6.1.
Thank you for an answer.
struct something {const float m = 3} s;` //actually 12 members. Compiler doesn't accept values: "ISO C++ forbids initialization of member"
to fix above do
struct something {
something (float const& f = 3) : m(f)
const float m;
} s;
The difference between struct and class in C++ is that structs default their members to public while classes default to private (same goes for inheritance). That's all there is to it.
Then, in C++03 const float m = 3; is not valid as a member declaration. You would need to declare a constructor for your struct:
struct something
{
const float m;
const float n;
something() : m(3), n(42) {}
} s;
Structs AND classes in C++ suffer from this problem. You can only declare a value in a class definition if the variable is static and shared among all the instances of the class. If your variable is const I think that may be a good choice.
A good solution for non-const variables is a simple one - assign the desired values to all the variables in the default constructor of your class or struct.
e.g
struct Something
{
float value;
Something():value(5.0f) {};
}

Why is operator= and copy-constructor NOT implicitly generated in this case?

I have a struct like this:
/* Renderable definition */
struct Renderable
{
Renderable(VertexBufferPtr vertexBuffer, const Mat4& wvpMatrix, const Mat4& worldMatrix, const Vec4& diffuseColor, const float specularFactor) :
mVertexBuffer(vertexBuffer), mTransform(wvpMatrix, worldMatrix), mMaterial(diffuseColor, specularFactor)
{
}
/* Transform definition */
struct Transform
{
Transform(const Mat4& wvpMatrix, const Mat4& worldMatrix) : mWVPMatrix(wvpMatrix), mWorldMatrix(worldMatrix)
{
}
const Mat4 mWVPMatrix;
const Mat4 mWorldMatrix;
};
/* Material definition */
struct Material
{
Material(const Vec4& diffuseColor, const float specularFactor) : mDiffuseColor(diffuseColor), mSpecularFactor(specularFactor)
{
}
const Vec4 mDiffuseColor;
const float mSpecularFactor;
};
const VertexBufferPtr mVertexBuffer;
const Transform mTransform;
const Material mMaterial;
};
/* RenderQueue definition */
typedef std::vector<Renderable> RenderQueue;
When I try to use it in my code like this;
RenderQueue CreateRenderQueue(const Scene* scene);
....
RenderQueue renderQueue(CreateRenderQueue(activeScene));
I get the follow compile error:
c:\program files (x86)\microsoft visual studio 10.0\vc\include\xutility(2514): error C2582: 'operator =' function is unavailable in 'Renderable'
After some digging I came to realise it was because I had not defined the assignment operator and the copy-constructor. I then did so, and voilah! it compiled...
....My question is however, why is the assignment operator and the copy constructor NOT implicitly generated by the compiler? (vs2010) I did not define them, so surely they would be generated?
Thanks
You have constant class member objects, so you cannot assign those. A copy constructor should be generated, though.
See the answer to this question, which states the conditions for an implicit default constructor (emphasis mine):
If you do not define a constructor, the compiler will define a default constructor for you
You defined a constructor, hence the implicit default one is not available anymore, it's up to you to define one.
In fact, a few lines below the same answer gives the same rule for all of the essential methods of classes:
If no destructor/copy Constructor/Assignment operator is defined the compiler builds one of those for you

C++ static const and initialization (is there a fiasco)

I am returning to C++ after a long absence and I am stumbling a little over my understanding of the fairly well known static initialization problem.
Let's say I have a simple class Vector2 as given below (note that I am aware that x and y should be private with getters and setters, these have just been omitted for brevity):
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {};
float x,y;
}
Now, if I want to specify a static const member to represent a Vector2 with x and y set to 1, I am unsure on how to proceed - will static const members fall foul of the static initialization problem or will the act of making them const mean they are ok? I am toying with the following possibilities:
Possibility 1:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2 ONE;
float x,y;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
Possibility 2:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
private:
static const Vector2 ONE;
};
// .cpp
const Vector2 Vector2::ONE = Vector2(1.f, 1.f);
static const Vector2& Vector2::getOne() {
return ONE;
}
Possibility 3:
// .h
class Vector2 {
public:
Vector2(float x, float y) :x(x), y(y) {}
static const Vector2& getOne();
float x,y;
};
// .cpp
const Vector2& Vector2::getOne() {
static Vector2 one(1.f,1.f);
return one;
}
Now, my preferred way to write this would be as in possibility 2, just because it is a more comfortable syntax for me. However, if I call the getOne() method from another static method in another class am I going to risk crashing and burning? As I say, it is because I am using a static const rather than a plain static that I am asking this question as I have found much on plain static class member issues, but nothing on const static issues.
I suspect that I gain nothing by the fact that I am using static const and will need to go with Possibility 3 to be safe, but I just want to ask in case someone can shed some light on this for me.
I realise I am probably opening myself up to a slew of links pointing to exactly what I am asking, but I have looked and not found before posting this.
Any help will be gratefully appreciated.
All of them, except possibility 3, suffer from the static initialization order fiasco. This is because your class is not a POD. In C++0x, this problem can be solved by marking the constructor constexpr, but in C++03 there is no such solution.
You can remove the constructor to solve the problem in C++03, and initialize using
const Vector2 Vector2::ONE = { 1.f, 1.f };
This is initializing a POD, and all initializers in the list are constant expression (for the purpose of static initialization). The intialization of them happen before any code is run that might access it before being initialized.
3.6.2:
Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place.
8.5.1/14:
When an aggregate with static storage duration is initialized with a brace-enclosed initializer-list, if all the member initializer expressions are constant expressions, and the aggregate is a POD type, the initialization shall be done during the static phase of initialization (3.6.2); otherwise, it is unspecified whether the initialization of members with constant expressions takes place during the static phase or during the dynamic phase of initialization.
Please note that possibility 3 is not thread safe.
See for example "C++ scoped static initialization is not thread-safe, on purpose!" at http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx