Override Class member array variable values

When I have an array as a class member variable and I want to override the default values by calling a separate constructor.

Is what I am doing the optimal way?

I am programming for embedded devices and using std::vector is not an option so I am using an array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>

class MyClass{
    private:
        static const int JOINT_SIZE = 4;
        int joints[4] = {2,16,4,12};
    public:
        MyClass(){};
        MyClass(int * newJoints){
            for (size_t i = 0; i < JOINT_SIZE; i++)
            {
                joints[i] = *newJoints + i;
            }
            
        }
        void printJoints(){
            for (size_t i = 0; i < JOINT_SIZE; i++)
            {
                std::cout << joints[i] << std::endl;
            }
            
        }
};

int main()
{
    // default constructor
    MyClass myClass;
    myClass.printJoints();

    // override joints
    int newJoints[4] = {5,7,9,10};
    MyClass myOverrideClass(newJoints);
    myOverrideClass.printJoints();


    return 0;
}
joints[i] = *newJoints + i; here, you are just adding the value of i(which gonna be 0,1,2,3) to the first element(5) of newJoints(the one in the main function), there is no pointer iteration here;

Change that line with:

joints[i] = *(newJoints+i);

or subscript it

joints[i] = newJoints[i];

Also be careful of going out of bounds

What is this embedded device of yours if I may ask?
Last edited on
Ohh thanks for pointing out my error.

How do I check out of bounds when doing pointer arithmetic? I am passing it manually on my own but it could be a possibility.

I am creating my own simple library using an ESP-01. Learning C++ and embedded programming at the same time.
Last edited on
How do I check out of bounds when doing pointer arithmetic? I am passing it manually on my own but it could be a possibility.


I meant in general.

Note: My c++ knowledge is only c++98, so I may not be much of help here, but do not worry, there are many veterans here that will provide much up-to-date information.

First; I do not see any need for JOINT_SIZE to be static, specially when it is constant int. I guess static could be needed when the value changes, and wanting updates from it.

Second; in your code, you can easily go out of bound, for example, if you change newJoints(the one in main) from int newJoints[4] = {5,7,9,10}; to int newJoints[3] = {5,7,9}; that's an out of bound error,
same if You change JOINT_SIZE = 4; to JOINT_SIZE = 5; That's another way to get an out of bound error.
You can expand the newJoint(the one in main) to be int newJoints[5] = {5,7,9,10,11}; the code will compile, no out-of-bound error, but the last value, wont be assigned in the constructor.

What is the problem here?
The problem is that your code rely on JOINT_SIZE and all arrays(joints and newJoints) to be exactly 4, and no one of them need to change. This can be easily managed if your program is small, as it increases in size, chances grow to fall in an out of bound bug, creating a constant in a namespace can solve this. and your code will be like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
namespace ns
{
    const int JOINT_SIZE = 4;

    class MyClass{
    private:
        int joints[JOINT_SIZE] = {2,16,4,12};
    public:
        MyClass(){};
        MyClass(int * newJoints)
        {
            for (size_t i = 0; i < JOINT_SIZE; i++)
                joints[i] = *(newJoints + i);
        }
        void printJoints()
        {
            for (size_t i = 0; i < JOINT_SIZE; i++)
                std::cout << joints[i] << ", ";

            std::cout << "\b\b \n";
        }
    };
}

int main()
{
    // default constructor
    ns::MyClass myClass;
    myClass.printJoints();

    // override joints
    int newJoints[ns::JOINT_SIZE] = {5,7,9,10};
    ns::MyClass myOverrideClass(newJoints,sizeof(newJoints)/sizeof(*newJoints));
    ns::MyClass myOverrideClass(newJoints);
    myOverrideClass.printJoints();

    return 0;
}


Now you can change JOINT_SIZE only once. In the namespace. and all others will follow, for as much joints as you want.

The only problem that remains here, is that if you forget for example to fill newJoint(the one in main) with ns::JOINT_SIZE elements. like:
int newJoints[ns::JOINT_SIZE] = {5,7,9};// Assuming here that ns::JOINT_SIZE is 4
The code will compile but the last element will be unknown.

If only I know a way to determine how many element the constructor gets (here 3), so that I can set the last to the default, or do something about it.


Last edited on
Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <cstring>

constexpr size_t JOINT_SIZE { 4 };

class MyClass {
private:
	int joints[JOINT_SIZE] { 2, 16, 4, 12 };

public:
	MyClass() {};
	MyClass(const int* newJoints) {
		std::memcpy(joints, newJoints, JOINT_SIZE * sizeof(int));
	}

	void printJoints() const {
		for (size_t i {}; i < JOINT_SIZE; ++i)
			std::cout << joints[i] << ' ';

		std::cout << '\n';
	}
};

int main() {
	const MyClass myClass;

	myClass.printJoints();

	const int newJoints[JOINT_SIZE] { 5, 7, 9, 10 };
	const MyClass myOverrideClass(newJoints);

	myOverrideClass.printJoints();
}



2 16 4 12
5 7 9 10

@ninaj01 - your L33 requires a constructor of 2 params, but there is only a constructor that takes 1 param.
Thank you @ninja01 for your points.

@seeplus

1
2
3
4
5
6
7
8
	const MyClass myClass;

	myClass.printJoints();

	const int newJoints[JOINT_SIZE] { 5, 7, 9, 10, 12 };
	const MyClass myOverrideClass(newJoints);

	myOverrideClass.printJoints();


I tried putting more joints in the array and I am getting
1
2
3
4
main.cpp:29:49: error: excess elements in array initializer
        const int newJoints[JOINT_SIZE] { 5, 7, 9, 10, 12 };
                                                       ^~
1 error generated.


And this is a good thing right? Because this was catch at compile time?
If you want 5, then you need to change L4 as required.

And this is a good thing right? Because this was catch at compile time?


It will catch buffer overflow which is good. But it would compile if you only had say 3 elements in newJoints - in which case the last non-set element(s) would be set to 0.
Got it! Thanks for the clear explanation!
@ninaj01 - your L33 requires a constructor of 2 params, but there is only a constructor that takes 1 param.


Sharp eyes @seeplus

I edit it.

About constexpr size_t JOINT_SIZE { 4 }; , aren't you declaring a global variable here? and what is this constexpr ?
Yes, it's global. But that's fine as it's a global constant.

constexpr is for an expression that can be evaluated at compile time as opposed to when the program is executed.
https://en.cppreference.com/w/cpp/language/constexpr
Topic archived. No new replies allowed.