C++ Initializing Non-Static Member Array

C++ Initializing Non-Static Member Array

If your requirement really permits then you can make these 5 arrays as static data members of your class and initialize them while defining in .cpp file like below:

class Robot
{
static int posLShd[5];
//...
};
int Robot::posLShd[5] = {250, 330, 512, 600, 680}; // in .cpp file

If that is not possible then, declare this arrays as usual with different name and use memcpy() for data members inside your constructor.

Edit:
For non static members, below template style can be used (for any type like int). For changing the size, simply overload number of elements likewise:

template<size_t SIZE, typename T, T _0, T _1, T _2, T _3, T _4>
struct Array
{
Array (T (&a)[SIZE])
{
a[0] = _0;
a[1] = _1;
a[2] = _2;
a[3] = _3;
a[4] = _4;
}
};

struct Robot
{
int posLShd[5];
int posLArm[5];
Robot()
{
Array<5,int,250,330,512,600,680> o1(posLShd);
Array<5,int,760,635,512,320,265> o2(posLArm);
}
};

C++11

The array initialization has now become trivial:

class Robot
{
private:
int posLShd[5];
...
public:
Robot() : posLShd{0, 1, 2, 3, 4}, ...
{}
};

Initializing non-static member array of size defined in a #define of class type without default ctor

You can do this pretty easily if you can assume that Bar is movable/copyable:

template <std::size_t ... Is>
std::array<Bar, sizeof...(Is)> make_bar_array_impl(Foo& f, std::index_sequence<Is...>) {
return { (Is, f)... };
}

template <std::size_t N>
std::array<Bar, N> make_bar_array(Foo& f) {
return make_bar_array_impl(f, std::make_index_sequence<N>{});
}

Foo() : myBars(make_bar_array<BARS_IN_FOO>(*this)) {}

This could easily refactored to use a more generic template metaprogramming utility of "repetition". I suspect that any template meta programming library will have some such utility, here I don't bother factoring it out since it is a one liner anyhow. But if you come across such problems often it's something to consider (just write a function that returns an N-entry initializer list all with the same expression).

Live example: http://coliru.stacked-crooked.com/a/aab004c0090cc144. Sorry couldn't easily access an MSVC compiler. Also compiled with 14 since I didn't need any 17 features.

Edit: even if Bar is not movable/copyable, or if you don't think things will get optimized, this technique can actually be modified to work even in that case. You can generate an array<std::reference_wrapper<Foo>, N instead. But this is a little bit more complex and typically in C++ most things should be movable, and usually constructor calls are not in the critical path. Still I can elaborate if necessary.

Edit2: also, please don't use a #define for that. constexpr static auto BARS_IN_FOO = 5; should work exactly the same way, except that it is properly namespaced (and probably some other macro nastiness I'm forgetting).

Any workarounds for non-static member array initialization?

One possible workaround is to avoid the compiler calling the OtherClass constructor at all, and to call it on your own using placement new to initialize it whichever way you need. Example:

  class Foo
{
private:
char inst[3*sizeof(OtherClass)]; // Array size fixed. OtherClass has no default ctor.

// use Inst to access, not inst
OtherClass &Inst(int i) {return (OtherClass *)inst+i;}
const OtherClass &Inst(int i) const {return (const OtherClass *)inst+i;}
public:
Foo(...)
{
new (Inst(0)) OtherClass(...);
new (Inst(1)) OtherClass(...);
new (Inst(2)) OtherClass(...);
}
~Foo()
{
Inst(0)->~OtherClass();
Inst(1)->~OtherClass();
Inst(2)->~OtherClass();
}
};

To cater for possible alignment requirements of the OtherClass, you may need to use __declspec(align(x)) if working in VisualC++, or to use a type other than char like:

Type inst[3*(sizeof(OtherClass)+sizeof(Type)-1)/sizeof(Type)];

... where Type is int, double, long long, or whatever describes the alignment requirements.

Use an array with non-static size inside of a class

There are basically 2 ways to solve this. If you want to keep the array, then you need to move the dimension sizes from being constructor parameters to being template parameters. Template parameters are known at compile time and can be used to create an array. That would look like

template <size_t a, size_t b, size_t c, size_t d>
class Value{
public:
double Matrix[a][b][c][d]{};

void Putavalueinside (double input, long Positiona, long Positionb, long Positionc, long Positiond) {
Matrix[Positiona][Positionb][Positionc][Positiond] = input;
}
};

int main()
{

//makes a class object
Value<3,4,5,6> Test;

//gives the Matrix a value
Test.Putavalueinside(10, 0, 0, 0, 0);

//prints it to the consol
std::cout << Test.Matrix[0][0][0][0];

}

If you don't know what the sizes will be at compile time then you are going to need to do some dynamic memory allocation. To handle this you can use a std::vector as the storage type of the matrix and then you can use math to pretend it is a 4d structure. That would look like

class Value{
public:
size_t a;
size_t b;
size_t c;
size_t d;
std::vector<double> Matrix;
Value(size_t a_, size_t b_, size_t c_, size_t d_) : a(a_), b(b_), c(c_), d(d_), Matrix(a_ * b_ * c_ * d_) {}

void Putavalueinside (double input, long Positiona, long Positionb, long Positionc, long Positiond) {
Matrix[Positiona + Positionb * a + Positionc * a * b + Positiond * a * b * c] = input;
}
double Getvalueinside (long Positiona, long Positionb, long Positionc, long Positiond) {
return Matrix[Positiona + Positionb * a + Positionc * a * b + Positiond * a * b * c];
}
};

int main()
{

//makes a class object
Value Test(3,4,5,6);

//gives the Matrix a value
Test.Putavalueinside(10, 0, 0, 0, 0);

//prints it to the consol
std::cout << Test.Getvalueinside(0, 0, 0, 0);

}


The formula for flattening an n-dimension array can be found here: 4D position from 1D index?

Non-static initialization of a flexible array member?

If this is an exam, and you must use a Flexible Array Member, then as I indicated in the comments and as @rici explained in his answer, the purpose of the FAM is to provide a placeholder of a given type that then allows you to allocate storage for the struct itself plus storage for some number of your FAM type in a single-allocation. The advantage this provides is a single-allocation/single-free rather than separate allocation for the struct and then allocating for some number of your needed type.

(prior to the FAM, there was what was referred to as the struct hack where an array of size 1 was used in its place for much the same purpose)

The type is critical to how you deal with and allocate for your FAM. In your case your FAM is item *items[]; (an array of pointers to type item -- Item in your code) So you allocate for the struct and then X number of pointers to item.

To initialize each member of items, you must assign a valid address to a struct of type item (or you can separately allocate, copy to the new block, and then assign the starting address for that block to a pointer in items) In your case, you have an array of struct item called fruits. To assign to items, you must assign the address of each struct to each element in items (remember you have storage for pointers, not storage for struct item -- and you must ensure fruits remains in scope for the duration of your use of basket)

Putting those pieces together, you could do something similar to the following:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

typedef struct {
int low, high;
char label[16];
} item;

typedef struct {
size_t length;
item *items[];
} item_coll;

char *find_first_in_range(item_coll *ic, int rlow, int rhigh)
{
for (size_t i = 0; i < ic->length; i++)
if (ic->items[i]->low >= rlow && ic->items[i]->high <= rhigh)
return ic->items[i]->label;
return NULL;
}

int main() {

item fruits[] = {
{10, 20, "Apple"},
{12, 14, "Pear"},
{ 8, 12, "Banana"},
{ 2, 4, "Grape"},
{15, 35, "Watermelon"}
};
size_t nfruits = sizeof fruits/sizeof *fruits; /* avoid magic-numbers */
/* allocate storage for basket + nfruits pointers */
item_coll *basket = malloc (sizeof *basket +
nfruits * sizeof *basket->items);
if (!basket) { /* validate allocation succeeded */
perror ("malloc-basket+5_item_coll");
return 1;
}
basket->length = nfruits; /* assign length */

for (size_t i = 0; i < nfruits; i++) /* assign addresses to structs */
basket->items[i] = &fruits[i];

char *label = find_first_in_range (basket, 12, 15); /* save return */
if (label) /* validate not NULL before printing */
printf ("%s\n", label);

free (basket); /* don't forget to free the memory you allocate */

return 0;
}

(note I have simply used typedefs and removed the struct labels themselves -- it's up to you. Further, you should validate the return from find_first_in_range is not NULL before printing.)

Example Use/Output

Also note I've bracket the high/low range for

$ ./bin/fam_initialization
Pear

Memory Use/Error Check

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/fam_initialization
==6887== Memcheck, a memory error detector
==6887== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6887== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==6887== Command: ./bin/fam_initialization
==6887==
Pear
==6887==
==6887== HEAP SUMMARY:
==6887== in use at exit: 0 bytes in 0 blocks
==6887== total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==6887==
==6887== All heap blocks were freed -- no leaks are possible
==6887==
==6887== For counts of detected and suppressed errors, rerun with: -v
==6887== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

Look things over and let me know if you have further questions.

C Programming - Non static initialization of a flexible array member

You need to create some space for the name of each card. Easiest way to do this would be to change your struct card definition to something like:

struct card
{
int value;
char name[16]; // doesn't have to be 16, but make sure it's large enough to hold each card name plus a '\0' terminator
};

Why do i get invalid use of non-static data member error when i try to create an array inside class?

int newArray[x]; won't work because size of a static array needs to be known at compile time. Adding static constexpr to the declaration of x makes it a compile time constant and that's why the code compiles.

int newArray = new int[x]; won't work either, because operator new returns a pointer, which cannot be assigned to an integer. Having said that, consider using std::vector instead.

Why do I need to member-initialize a non-static array member in a constexpr class?

Consider the semantics.

Omitting the member from the initialization list will perform default initialization, which in this case leaves the array with unspecified values. That negates the purpose of a constexpr.

Value initializing the array performs zero initialization on each array element (since this is an array of built in types).



Related Topics



Leave a reply



Submit