re-initialize a struct's members - c++

It's easy to create and initialize a struct...
struct S{ int x; bool b; };
S s = {123,false};
But is it possible to use the same trick on an existing object? Or is this a 1-time only thing?
S s = {123,false};
s = {456,true}; //fails
s = S(){456,true}; //fails
Is there a syntax trick... obviously I could do:
S s = {123,false};
S temp={456,true};
s = temp;
But can I remove explicitly declaring the temp variable?
I should add I'm working on VC++ 2008, so no fancy modern C++ stuff is available :(

No. Initialization is a one time occurrence. Initialization occurs only when you create as well as assign some values to the created object at the same time (i.e., in one statement0.
Once the object is created you can only assign new values to it.
In short,
You can't reinitialise anything in C++. You can initialise objects or you can assign them.
Once you understand this fact, you can see that there are number of solutions possible such as
passing the structure members to the constructor & creating the structure object of it
overloading the =operator to do whatever you want

You could add a constructor to your struct and then you could do something like:
struct S
{
S(int x_in, bool b_in): x(x_in), b(b_in) { }
int x;
bool b;
}
S s(123, false);
s = S(456, true);

In c++11 you can:
s = S({456, true});

In C++11, an you can construct a temporary from an initializer list and use it with assignment operator. Thus you can write:
struct S {
int x;
bool b;
};
int main()
{
S s = {42, true};
s = {0, false};
}

I dont think struct would support re initialization by default.
S s = {123,false};
S temp={456,true};
s = temp; //calls the = operator
Maybe you could try overloading the assignment operator
Or you can try creating temp on the fly.
S s = {123,false};
s = S (456,true); // this should work i suppose

Related

Initialise array of struct with const fields which don't have a default constructor

I want to define an array of structs, but this is not working because it has a const field without default constructor.
Struct is part of an SDK and looks like following:
struct SParametricParamDef
{
const TXString fUniversalName;
SResString fLocalizedName;
const TXString fDefaultImperial;
const TXString fDefaultMetric;
EFieldStyle fFieldStyle;
short fChoicesChcID;
};
TXString does not have a default constructor. So following is failing:
SParametricParamDef *arrParams = new SParametricParamDef[size]; // <= throws compile time exception
for (int i = 0; i < size; i++)
{
arrParams[i] = params[i].def; // <= also throws an exception, because operator = is not available
}
Is there some way to solve this? I need an SParametricParamDef* as a result, because this array is used in the SDK again...
Info
In an old SDK version, const TXSTring was const char* and back then I did not have problems... Now I need to adjust my code to work with the new structures...
The error you get is not primarily about operator = but about the fact that you default-constructed an object with const members. This will render them immutable and any attempt to modify them, as you are trying in the loop, must fail.
Fortunately, you can use emplace_back to initialize the SParametricParamDef objects right inside the vector without taking the indirection of default-construction and assignment:
std::vector<SParametricParamDef> arrParams;
for(std::size_t n = 0; n < size; ++n) {
arrParams.emplace_back(params[n].def);
}
This should minimize the amount of copying and comes without the need to modify the struct definition.
The compiler is telling you that you are asking for a TXString to be created without directing how it can be initialised. It is difficult to know how to address the problem of creating a TXString object since you haven't given a list of the constructors for the class, but as it stands a change would need to be made to the code you've given. Some ways of solving this are as follows:
The most obvious is to add a default constructor for SParametricParamDef which initialises the TXString objects:
struct SParametricParamDef
{
SParametricParamDef() : fUniversalName(...), ... {}
...
Another approach, given that the variables are const might be to make them const static
Say, for simplicity's sake, that the TXString object was as follows:
struct TXString{
TXString(char a) : _a(a) {}
char _a;
};
You could then change your declaration of SParametricParamDef to:
struct SParametricParamDef
{
const static TXString fUniversalName;
...
and then define fUniversalName in your implementation file as follows:
const TXString SParametricParamDef::fUniversalName('D');
Another way might be to wrap a TXString object in another object that does have a default constructor:
struct TXStringWrapper {
TXStringWrapper() : _s(...) {} // [1]
const TXString& get() { return _s; }
private:
TXString _s;
}
At [1], you create the TXString in whatever specific, non-default way that you care.
That looks like an example for using a placement new:
SParametricParamDef *arrParams = (SParametricParamDef *) new char[size * sizeof(*arrParams)];
for (int i = 0; i < size; i++)
{
// constructs an object in a pre-allocated memory
new(arrParams+1) SParametricParamDef(params[i].def);
}
You should explicitely call a destructor if it is not trivial before freeing the array:
for (int i = 0; i < size; i++)
{
~SParametricParamDef(arrParams+1);
}
delete[] ((char *) arrParams);
This is rather old fashioned because it mimics the initialization of structs in C, but it is the only way I know to build an array of objects that only have non trivial constructors (AFAIK, the std::vector way requires copyable or movable objects)

Default nested structure initialization

Is there a syntax to initialize DataItem dh.size element to sizeof(DataItem)? The code below uses constructor and relying on compiler to optimize things to constant values. Not the perfect solution... Is there a syntax to initialize nested structs?
struct DataHeader_t {
int sz = 0;
int type = 0;
};
struct DataItem {
DataItem() {dh.sz = sizeof(DataItem);}
DataHeader_t dh;
float data1 = 0;
float data2 = 0;
...
};
Not the perfect solution... Is there a syntax to initialize nested structs?
Yes, that structure is called constructor, and you're already using it.

Concise way to initialize a vector of user-defined datatype

Okay, so I have a structure(below) and I want to initialize all its member to false. I also want a vector of size stalls of the structure barn. In other words, I want stalls copies of object structure barn with vector as container, and its members initialized.
struct barn {
bool cow, board;
};
I have been using the following code to do so (terrible way of doing it):
vector<barn> barn_info;
for (int i = 0; i != stalls; ++i) {
barn x; x.cow = false; x.board = false;
barn_info.push_back(x);
}
There are multiple ways of doing that, most of them involve C++11:
If (and only if) you are using C++11, you can have
struct barn {
bool cow = false;
bool board = false;
}
vector<barn> barn_info(stalls);
Note that this does not work together with initializing them on the contructor. See this link for more on them.
If you do not want to have a constructor for a struct AND you don't initialize its fields as above, you can have something like this:
vector<barn> barn_info(stalls, {false, false})
The { } part are also described in the above link. You can see more ways of initializing a std::vector here.
You can use the .assign() method of the std::vector, like this:
std::vector<barn> barn_info;
barn b; b.cow = false; b.board = false;
barn_info.assign(stalls, b); // assign 'stalls' positions the 'b' value
This works even if not using C++11. If using C++11 you can shorten it like:
barn_info.assign(stalls, {false, false});
struct barn {
bool cow, board;
barn():cow(false),board(false){}
};
vector<barn> barn_info(n);
Use the vector constructor directly :
barn b {false, false; };
std::vector<barn> barn_info (stalls, b);

Working with objectives and calling methods?

I've probably become a bit to used to Java and am finding this harder than it should be. Heres what I have.
myObject[0] = new item1(this);
class item1
{
private:
int x;
int y;
public:
item1( passedPointer* pOne )
{
x = 5;
y = 5;
}
int returnX() { return x; }
int returnY() { return y; }
}
Then in another method I thought I could just say:
void check()
{
int y = item1.returnY();
int x = item1.returnX();
}
But I am getting the common error: a nonstatic member reference must be relative to a specific object.
There is only one instance of this class item1, what would be the best way to do this? This is just a simplified fragment of what I'm actually doing, not the actual code.
Item1 is a class. You have to create an instance of it before you can access its non-static members. Try looking here for some basic information.
void check(){
int y = item1.returnY;
int x = item1.returnX;
}
This would also be incorrect in Java, since neither returnX nor returnY are statics, you need an object on which to apply the operation, and you also need the parenthesis of the method call:
void check() {
item1 i;
int y = i.returnY();
int x = i.returnX();
}
Perhaps implementing the Singleton pattern would not do you harm, since you want only one instance of the object. You could declare the object as global or static to a function too, then get the values.
Then again, you could also declare the functions as static, and add another one to initialize the static values of the variables which need to be returned by those methods. There are a lot of solutions to this depending on your situation which can not be fully grasped by the short amount of code you have pasted.
You created an instance of class item1 with the line
myObject[0] = new item1(this);
Unlike JAVA, in C++ there are pointers and new returns a pointer to the object (so myObject[0] is a pointer to the instance) so you need the -> operator. To activate the method you should write:
myObject[0]->returnX();
If you wish to have only one instance than implement the class as a singleton.

A variable that is read-only after assignment at run-time?

Fairly new programmer here, and an advance apology for silly questions.
I have an int variable in a program that I use to determine what the lengths of my arrays should be in some of my structures. I used to put it in my header as a const int. Now, I want to fork my program to give the variable different values depending on the arguments given in, but keep it read-only after I assign it at run-time.
A few ideas I've had to do this. Is there a preferred way?
Declare a const int * in my header and assigning it to a const int in my main function, but that seems clunky.
Make it a plain int in my main function.
Pass the variable as an argument when the function is called.
Something else I haven't thought of yet.
I'd use a function-static variable and a simple function. Observe:
int GetConstValue(int initialValue = 0)
{
static int theValue = initialValue;
return theValue;
}
Since this is a function-level static variable, it is initialized only the first time through. So the initialValue parameter is useless after the first run of the function. Therefore, all you need to do is ensure that the first call of the function is the one that initializes it.
C++ doesn't have a built-in solution for this, but if you really want to make sure that your int is only assigned once, you can build your own special int class:
class MyConstInt
{
public:
MyConstInt(): assigned(false) {}
MyConstInt& operator=(int v)
{
assert(!assigned);
value = v;
assigned = true;
return *this;
}
operator int() const
{
assert(assigned);
return value;
}
private:
int value;
bool assigned;
};
MyConstInt mi;
// int i = mi; // assertion failure; mi has no value yet
mi = 42;
// mi = 43; // assertion failure; mi already has a value
int* array = new int[mi];
When exactly do you know the correct value? If you read it from a file or whatever, you can just say:
const int n = determine_correct_value();
I'm tempted to say that what you want doesn't make sense. A constant is something that doesn't change its value, not something that maybe changes its value once or twice. If you want a global variable, just make it non-constant.
On the other hand, if you have scope-constant values, you would just declare and initialize them at the same time, following the general C++ guideline to declare as close to the usage site as possible. For example, mark the use of constants in the following local scope:
for (auto it = v.begin(), end = v.end(); it != end; ++it)
{
const Foo & x = *it;
const std::size_t n = x.get_number_of_bars();
// use x and n ...
const bool res = gobble(x, zip(n));
if (res && shmargle(x)) { return 8; }
}
Here the compiler may even choose not to generate any special code for the variables at all if their value is already known through other means.