Convert C array literal to work in C++ constructor? - c++

I have some C code that I'm trying to convert/wrap into a C++ class. I ran into some C literal arrays(correct me if I'm calling them wrong) and I'm not sure how to initialize them in the C++ constructor since I don't think you can do literals, which I think are compile time specific, to something that is runtime specific.
Should I just explicitly define the array to be of a certain size and just do a strcpy, or some such, of the literal to the array in the constructor?
char sysUpTime[] = {1,3,6,1,2,1,1,3,0};

As an alternative to initializer lists or string manipulation, you could use something like the following (if you really wanted to):
struct Wrapper
{
template <size_t N>
Wrapper(const char(&arr)[N]) : vec(arr, arr+N) { }
vector<char> vec;
};
I've left everything public due to chronic laziness on my part :). You can then initialise like this:
char foo[] = { 1, 2, 3, 4, 5 };
Wrapper bar(foo);
copy(bar.vec.begin(), bar.vec.end(), ostream_iterator<int>(cout, ", "));

Could just use std::string to store OID then initialize it in member initializer list for example:
#include <string>
class Wrapper
{
public:
Wrapper() : sysUpTime("1.3.6.1.2.1.1.3.0") { }
private:
std::string sysUpTime;
};
Or use C++11 std::array
class Wrapper
{
public:
Wrapper() : sysUpTime{{1,3,6,1,2,1,1,3,0}} { }
public:
std::array<char, 10> sysUpTime;
};

The main problem when passing different size c-style arrays to a constructor is that you must pass the size along with it. Here's an example of putting the array into a member vector:
#include <vector>
#include <iostream>
struct Test
{
std::vector<char> sysUpTime;
Test(const char sysUpTime[], size_t size) :
sysUpTime(sysUpTime, sysUpTime + size)
{ }
};
int main()
{
const char sysUpTime[] = {1,2,3,4,5};
Test test(sysUpTime, sizeof(sysUpTime) / sizeof(char));
}
Unfortunately I know of no way to do this without using a dynamic array (vector), aside from using templates which means that you'll get a separate class instantiated for each and every change in the size of your array.

Related

C++ static array initialization with indexes

I have a static array in a class and an enum for the index of such array.
enum MyEnum
{
FIRST = 0,
SECOND,
LAST
}
class MyClass
{
public:
static string names[LAST];
}
I'd like to initialize my static array to associate a value of the array to each enum type like this:
names[FIRST] = "First";
names[SECOND] = "Second";
I know that I can initialize the array upon declaration like this static string names[] = {"First", "Second"}, but I want to explicitly assign the value to the corresponding enum to avoid errors.
In Java, there's a static block where you can do this kind of initialization, but I don't think that this is the case in C++. Is there an elegant way of doing this? I can't use std on my project, so the solution has to avoid any library usage.
Thanks in advance.
Write a function to initialize it. Function can't return an array - if you want to use an array, return a whole object that has an array inside it. Or you can return something dynamically allocated, a map or a vector.
#include <array>
#include <string>
enum MyEnum {
FIRST = 0,
SECOND,
LAST
};
std::array<std::string, LAST> construct_names() {
std::array<std::string, LAST> r;
r[FIRST] = "first";
r[SECOND] = "second";
return r;
}
static auto names = construct_names();
I can't use std on my project, so the solution has to avoid any library usage.
Roll your own types.
enum MyEnum {
FIRST = 0,
SECOND,
LAST
};
template<typename T, unsigned N>
struct MyArray {
T data[N];
T &operator[](unsigned i) {
return data[i];
}
};
MyArray<const char *, LAST> construct_names() {
MyArray<const char *, LAST> r;
r[FIRST] = "first";
r[SECOND] = "second";
return r;
}
static auto names = construct_names();
You may also want to read How to initialize private static members in C++? or similar, as for class initialization you need to do like, there will be some type repetition:
class MyClass {
public:
static MyArray<const char *, LAST> names;
};
MyArray<const char *, LAST> MyClass::names = construct_names();
Yes you can do it in simple way using __attribute__((init_priority(101))) and __attribute__((constructor(102)))
#include <string>
#include <iostream>
using namespace std;
enum MyEnum
{
FIRST = 0,
SECOND,
LAST
};
class MyClass
{
public:
static string names[LAST];
};
__attribute__((init_priority(101))) string MyClass::names[LAST];
__attribute__((constructor(102))) void foo()
{
MyClass::names[FIRST] = "First";
MyClass::names[SECOND] = "Second";
}
int main()
{
MyClass m;
for (int i = 0; i < LAST; i++) {
cout << m.names[i] << "\n";
}
}
Output:
First
Second
Explanation in simple:
Before even code loads, first it initialize string MyClass::names[LAST]; because we added __attribute__((init_priority(101))) then it calls foo() automatically, The function name can be any it does not matter, it can be init as well no need to be foo. The order of initialization is based on number 101 and 102. If we change the order then it wont work.
For more info refer: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-init_005fpriority-variable-attribute
Declaimer: This initialization is not bound to the class, if you keep on adding like this for all the classes then you are in big trouble and you need to keep on maintain a list of orders. This inits are for the entire binary or library

How do you assign array values to class member array in constructor, without using the std library?

Trying to understand the proper way to copy values into an class member array. Currently, I take each value of the array and copy them into the corresponding element of the member array:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values[0], values[1], values[2], values[3]}
{
}
const unsigned char values[4];
};
int main(int argc, char** argv)
{
unsigned char values[] = {10, 0, 0, 1};
IPAddress address(values);
return 0;
}
This works, but is there a way to "automagically" copy all the values in the constructor? I mean, what would I do if the values were of a class had 100 elements instead of 4? Or 1000?
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
Any takers?
You should be using std::array. This is one part of the standard library that shouldn't be offensive to embedded programming.
If you don't have access to it, it's not hard to implement a class just like it. It's a straight forward aggregate with saner semantics than raw arrays. It's also likely to be reused, which makes it a good candidate for a utility you should implement.
Failing that, you can rely on delegating c'tors, which I only add here for the intellectual exercise:
struct IPAddress
{
IPAddress(const unsigned char values[4])
: IPAddress(values, std::make_index_sequence<4>{})
{
}
const unsigned char values[4];
private:
template<std::size_t... I>
IPAddress(const unsigned char values[4], std::index_sequence<I...>)
: values{values[I]...}
{
}
};
The key is in the pack expansion values{values[I]...}, which turns into an initializer not unlike your original one. See it live.
I'm aware that I should be using std::array. But since this code is built for a microcontroller, using std library is not really an option.
If you don't want to include array, you can still implement your own type for solving your issue:
template<typename T, std::size_t N>
class values_t {
public:
values_t(const T *ptr) {
// copy N elements
for (std::size_t i = 0; i < N; ++i)
value[i] = ptr[i]; // copy element
}
T& operator[](int i) { return value[i]; }
const T& operator[](int i) const { return value[i]; }
private:
typename std::remove_const<T>::type value[N];
};
Then, initializing the values data member of IPAddress becomes much simpler:
struct IPAddress
{
IPAddress(const unsigned char values[4]) :
values{values} {} // <-- copy as a whole
values_t<const unsigned char, 4> values;
};

Inheritance and array of types

I have a probably very simple question in C++.
Let's say I have class defined as:
class PS
{
private:
int value;
int m;
public:
PS();
PS(int value, int m);
PS(int m);
};
Now I want to define an array with elements of this type. For example,
PS t[3];
However, I want all of the elements in this array to have m=2. How would I do that? I am assuming I have to use inheritance some how, right?
So for example I don't want to do something like this:
>PS t[3];
>t[0].PS(2);
>t[1].PS(2);
>t[2].PS(2);
I want to do it one show for all elements of t.
Using your constructor, you can simply use brace initialization :
PS t[] = { PS(2) , PS(2), PS(2) };
Or as suggested by #0x499602D2, since PS has a non explicit constructor, simply :
PS t[] = { 2, 2, 2 };
I would also suggest you to use std::array<> instead of C-style arrays.
It is not really safe not to initialize a value but you can use the C++11 feature that allows you to initialize variable directly in your class definition :
class PS {
private:
int value;
int m = 2;
public:
PS() {};
};
If you are using an older version of C++ you can consider overloading the default constructor
class PS {
private:
int value;
int m;
public:
PS(int _m = 2) : m(_m) {};
};
The STL Vector class is preferred to c-arrays. Using one, you could do:
std::vector<PS> t(3, PS(2));

Set Array to an Initialized, Passed-In Array in C++

Pardon the extraordinarily basic question, but as a Java programmer this C++ error is not exactly "clicking", so to speak.
I want to create and initialize an array in one function, then pass that array to another function. Within the receiving function, I'd like to access elements of the passed-in array.
As an (abbreviated) example:
class demo{
main() {
int members[] = { 1, 2, 3, 4, 5 };
example.function(members);
}
}
Which would pass array members to the following function:
class example {
int members[];
void function(int mem[]) {
members = mem;
}
}
Which gives me the error:
error: incompatible types in assignment of ‘int*’ to ‘int [0]’
I want example.members[] to equal demo.members[]. I understand why I'm getting an int* in example.function, but can't figure out how to set up the array in class example.
Just do it the C++ way, and use std::vector:
#include <vector>
class example {
std::vector<int> members;
void function(std::vector<int> const& mem) {
members = mem;
}
};
In C++11 you could avoid the copy when an rvalue is provided (such as in: ex.function({1, 2, 3})) by letting function() take its argument by value and then move it into the data member:
#include <vector>
class example {
std::vector<int> members;
void function(std::vector<int> mem) {
members = std::move(mem);
}
};
Change the private member variable example::members to type int *.
class Example {
int *members;
void function(int *mem) {
members = mem;
}
}
void main () {
int array[] = { 1, 2, 3, 4, 5 };
Example ex;
ex.function(array);
}
You can not directly assign regular array, if you really want to use regular array, you need to do it in a loop.
Try to use std::vector or std::array ( std::array documentation) instead.
For example: std::vector way:
class example {
std::vector<int> members;
void function(const std::vector<int>& mem) {
members = mem;
}
}

How to declare a constant array in class with constant class variable?

How to declare a constant array in class with constant class variable? Is it possible.
I don't want dynamic array.
I mean something like this:
class test
{
const int size;
int array[size];
public:
test():size(50)
{}
}
int main()
{
test t(500);
return 0;
}
the above code gives errors
No, it's not possible: As long as size is a dynamic variable, array[size] cannot possibly be implemented as a static array.
If you like, think about it this way: sizeof(test) must be known at compile time (e.g. consider arrays of test). But sizeof(test) == sizeof(int) * (1 + size) in your hypothetical example, which isn't a compile-time known value!
You can make size into a template parameter; that's about the only solution:
template <unsigned int N>
class Test
{
int array[N];
static const unsigned int size = N; // unnecessary really
public:
// ...
};
Usage: Test<50> x;
Note that now we have sizeof(Test<N>) == sizeof(int) * (1 + N), which is in fact a compile-time known value, because for each N, Test<N> is a distinct type.
You mean a fixed sized array? You could use std::array like this:
#include <array>
class test
{
static const size_t s_size = 50;
std::array<int, s_size> m_array;
public:
test()
{
}
};
Or if you want to support different sizes you need to resort to a class template like this:
#include <array>
template <size_t SIZE>
class test
{
std::array<int, SIZE> m_array;
public:
test()
{
}
};
std:array has the added benefit of keeping the size information along with the member (unlike arrays which decay to pointers) and is compatible with the standard library algorithms.
There is also a version that Boost offers (boost::array) which is similar.
Your code yields an error because compiler needs to know the size of data type of each member. When you write int arr[N] type of member arr is "an array of N integers" where N must be known number in compile time.
One solution is using enum:
class test
{
enum
{
size = 50
};
int arr[size];
public:
test() {}
};
Another is declaring size as static const member of class:
class test
{
static const int size = 50;
int arr[size];
public:
test(){}
};
Note that in-class initialization is allowed only for static class integers! For other types you need to initialize them in code file.