I have the following class in C++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?
This doesn't work:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
Edit: The case in point is when I can have different values for b for different instances, but the values are known to be constant for the lifetime of the instance.
With C++11 the answer to this question has now changed and you can in fact do:
struct a {
const int b[2];
// other bits follow
// and here's the constructor
a();
};
a::a() :
b{2,3}
{
// other constructor work
}
int main() {
a a;
}
Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).
std::vector uses the heap. Geez, what a waste that would be just for the sake of a const sanity-check. The point of std::vector is dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.
#include <stdio.h>
template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
size_t length;
public:
ConstFixedSizeArrayFiller() : length(0) {
}
virtual ~ConstFixedSizeArrayFiller() {
}
virtual void Fill(Type *array) = 0;
protected:
void add_element(Type *array, const Type & element)
{
if(length >= MaxLength) {
// todo: throw more appropriate out-of-bounds exception
throw 0;
}
array[length] = element;
length++;
}
};
template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
Type array[Length];
public:
explicit ConstFixedSizeArray(
ConstFixedSizeArrayFiller<Type, Length> & filler
) {
filler.Fill(array);
}
const Type *Array() const {
return array;
}
size_t ArrayLength() const {
return Length;
}
};
class a {
private:
class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
public:
virtual ~b_filler() {
}
virtual void Fill(int *array) {
add_element(array, 87);
add_element(array, 96);
}
};
const ConstFixedSizeArray<int, 2> b;
public:
a(void) : b(b_filler()) {
}
void print_items() {
size_t i;
for(i = 0; i < b.ArrayLength(); i++)
{
printf("%d\n", b.Array()[i]);
}
}
};
int main()
{
a x;
x.print_items();
return 0;
}
ConstFixedSizeArrayFiller and ConstFixedSizeArray are reusable.
The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become const after this initialization.
The second allows the array to be allocated inside another object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.
b_filler is a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.
I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.
ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:
a::a(void) :
b({2,3})
{
// other initialization stuff
}
Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:
#include <iostream>
class A
{
public:
A();
static const int a[2];
};
const int A::a[2] = {0, 1};
A::A()
{
}
int main (int argc, char * const argv[])
{
std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
return 0;
}
The output being:
A::a => 0, 1
Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:
#include <iostream>
class A
{
public:
A();
int a[2];
};
A::A()
{
a[0] = 9; // or some calculation
a[1] = 10; // or some calculation
}
int main (int argc, char * const argv[])
{
A v;
std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
return 0;
}
Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.
#include <stdio.h>
#include <stdlib.h>
class a {
static const int b[2];
public:
a(void) {
for(int i = 0; i < 2; i++) {
printf("b[%d] = [%d]\n", i, b[i]);
}
}
};
const int a::b[2] = { 4, 2 };
int main(int argc, char **argv)
{
a foo;
return 0;
}
You can't do that from the initialization list,
Have a look at this:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:)
A solution without using the heap with std::vector is to use boost::array, though you can't initialize array members directly in the constructor.
#include <boost/array.hpp>
const boost::array<int, 2> aa={ { 2, 3} };
class A {
const boost::array<int, 2> b;
A():b(aa){};
};
How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:
class a {
int privateB[2];
public:
a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
int b(const int idx) { return privateB[idx]; }
}
Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.
a aobj(2,3); // initialize "constant array" b[]
n = aobj.b(1); // read b[1] (write impossible from here)
If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.
interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:
readonly DateTime a = DateTime.Now;
I agree, if you have a const pre-defined array you might as well make it static.
At that point you can use this interesting syntax:
//in header file
class a{
static const int SIZE;
static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.
Related
Dear StackOverFlowers,
I'm having trouble passing a const char* [] to an object. The scenario is as follows.
I have a class UlamScreen which contains a const char* [] with several strings. UlamScreen also contains an object homeScreenMenu.
class UlamScreen {
const char* homeScreenText[5] = {"EVA dun", "Sabine", "TPU dun", "test Wout",
UlamScreenMenu homeScreenMenu;
};
class UlamScreenMenu {
private:
const char* _menuText[];
public:
UlamScreenMenu(const char*[]);
void drawMenu();
};
I want to pass the const char* [] to UlamScreenMenu so I can use it in a member function called void drawMenu, like this:
void UlamScreenMenu::drawMenu() {
for (int i = 0; i < menuItems; i++) {
tft.println(_menuText[i]);
}
}
I passed it to UlamScreenMenu's constructor like this:
UlamScreen::UlamScreen() : homeScreenMenu(homeScreenText) {
}
UlamScreenMenu::UlamScreenMenu(const char* menuText[], int length) {
for(int i = 0; i < length; i++) {
_menuText[i] = menuText[i];
}
}
I thought this would work, but for some reason, it does not. tft.println(_menuText[i]); used with void drawMenu does not send anything to my tft screen. When I use tft.println(_menuText[i]); from within the UlamScreen class it works perfectly.
Just to be clear, I can use the tft object within the UlamScreenMenu class because other functions like tft.drawRect() are working correctly.
What is wrong with this way of passing the const char* []? Thanks in advance.
In C++, you can't declare a member variable of type const char* x[], since this would denote a flexible array member. Flexible array members are a C-feature allowing the last member of a struct to be an array of varying size (cf., for example, Arrays of unknown size / flexible array members). Having parameters of type const char* x[] in functions, however, is supported and has basically the same meaning as const char** x.
If you stick to a member of type const char**, then you'll have to handle memory management in that class. This means: take care of allocating, deallocating, copying, moving, copy-assigning, and move-assigning objets of that class (cf, for example, the rule of 0/3/5).
If - as suggested in the comments - you use standard library collections, e.g. std::vector, these classes will do all this stuff in a reliable manner for you. See the following example illustrating the difference between both:
Note that the C++-version probably would not even take a const char*[]-parameter but directly a const std::vector<const char*> &x-parameter. But I kept the const char*[]-parameter in the constructor to provide the same interface in both variants:
// Variant 1: "old" C-style:
class Menu {
public:
Menu(const char* x[], int length) {
m_x = new const char*[length];
m_length = length;
for (int i=0; i<length; i++) {
m_x[i] = x[i];
}
}
~Menu() {
delete[] m_x;
}
// TODO: implement copy- and move constructors + copy- and move assignments
// ...
void print() {
for (int i=0; i<m_length; i++) {
std::cout << m_x[i] << std::endl;
}
}
private:
const char** m_x = nullptr;
int m_length;
};
#include <vector>
// Variant 2: a C++- way:
class Menu2 {
public:
Menu2(const char* x[], int length) {
m_x.assign(x, x+length);
}
void print() {
for (auto s : m_x) {
std::cout << s << std::endl;
}
}
// Menu2 does not manage memory on its own, hence:
// No special copy/move - constructors/assignments to be implemented.
// No special destructor necessary
private:
std::vector<const char*> m_x;
};
int main() {
const char* x1[3] = {"one","two","three" };
const char* x2[2] = {"eins","zwei" };
// Variant 1
Menu m1(x1, 3);
m1.print();
// Variant 2
Menu2 m2(x2, 2);
m2.print();
}
I have a class that needs to use some big arrays, initialized via some complex functions, that will be the same for every instance and will only be read after initialization.
I searched on SO and found some answers on initializing static arrays like this:
char A::a[6] = {1,2,3,4,5,6};
But in my case I need to calculate the arrays at runtime via some function.
(How) can I do it?
Re
” will be the same for every instance and will only be read after initialization
Producing a value is the job of a function.
Just define a function that returns the data you need.
You can use it to initialize a static data member (or whatever). For a header only module, if that's relevant, you will need to employ solution to the "inline data" problem, e.g. a Meyers' singleton (a function that returns a reference to a local static variable). Like this:
#include <vector>
namespace my {
using std::vector;
inline
auto squares()
-> vector<int>
{
vector<int> result;
for( int i = 1; i <= 12; ++i ) { result.push_back( i*i ); }
return result;
}
class A
{
private:
static
auto a()
-> const vector<int>&
{
static const vector<int> the_values = squares();
return the_values;
}
public:
A(){}
};
} // namespace my
You can't use {} sintaxis in execution time, you can use a method:
class A
{
static vector<char> a;
//...
public:
static void initStatic();
}
void A::initStatic()
{
a.resize( /*put the size here... */);
for (auto& x : a)
x = //something...
}
vector reference: http://en.cppreference.com/w/cpp/container/vector
If you aren't using vectors, this works. The reason I let A::initialize do the work, rather than just calling one of these externally defined functions, is that we can and should expect the data member a to be private.
//Declare a function pointer type, so you can pass it into A's
//an initialization function takes in the array and its size
typedef void (*initFunction) (char A[], int arraySize);
//see http://www.cprogramming.com/tutorial/function-pointers.html
// for more on function pointers
class A
{
public:
void initialize (initFunction myInitFunction);
...
private:
char a[ARRAYSIZE];
};
void A::initialize (initFunction myInitFunction)
{
(*myInitFunction) (a, ARRAYSIZE);
}
...
A myA;
myA.initialize (yourArrayInitializingFunction);
Or maybe your initialization functions don't take in arrays and initialize them, but return arrays:
class A
{
public:
void initialize (const char* aInit);
...
};
void A::initialize (const char* aInit)
{
for (int i = 0; i < ARRAYSIZE: ++i)
a[i] = aInit[i];
}
...
A myA;
myA.initialize (yourArrayReturningFunction ());
If you're using vectors, code is simpler:
class A
{
public:
void initialize (const vector<char>& aInit) { a = aInit; }
...
private:
vector<char> a;
};
My suggestion:
Instead of using a static member variable, use a static member function to provide access to the array.
In the static member function, create a static function variable that can be populated the first time it is needed.
Here's what I am thinking of:
char* A::getArray()
{
static char a[6] = {0};
static bool inited = false;
if ( !inited )
{
// Initialize the array elements
a[0] = ... ;
...
a[5] = ... ;
inited = true;
}
return a;
}
I come from Java and Ruby so I have a hard time coding simple stuff in c++, c++ being harder to tame...
I want to initialize an array in the class constructor with predefined values that can be accessed by all methods in the class. Yeah, basic stuff.
In other words, I want to do something like this:
Box.h
class SomeClass
{
public:
SomeClass(int something);
SomeMethod();
DoSomething(int thing);
protected:
int _something;
int[] arr;
};
Box.cpp
SomeClass::SomeClass(int something) : something(_something)
{
arr ={16,2,45,65,45};
for (int x = 0; x < 5; x++)
arr[i] = arr[i] * _something;
}
SomeClass::SomeMethod(){
for (int x = 0; x < 5; x++)
DoSomething(arr[i]);
}
SomeClass::DoSomething(int thing){
//whatever
}
How?
#include <iostream>
//#include <initializer_list>
#include <array>
#include <algorithm>
class foo
{
public:
foo() : values({{16,2,45,65,45}})
{
// I left the below commented out in case you want to research more and use other kinds of types for doing it.
//std::initializer_list<int> list = {16,2,45,65,45};
//std::copy(std::begin(list), std::end(list), std::begin(values));
}
void print()
{
std::for_each(std::begin(values), std::end(values),
[](int v) { std::cout << v << ' '; });
}
private:
static const int SIZE = 5;
std::array<int, 5> values;
};
int main()
{
foo fooInstance;
fooInstance.print();
return 0;
}
The above is the best that I could do in a short period of time. I tested with the following compiler. You could use that as a starting point and see if you can learn other ways of doing it. Algorithms such as generate can also be used with lamda expressions in order to generate a controlled set of values (as opposed to a hard coded list as in our examples).
http://www.compileonline.com/compile_cpp11_online.php
You have options for initializing array data members, and two types or array you can use:
Using a C-style array,
struct Foo
{
int a[5] = {1,2,3,4,5}; // initialization at point of declaration
};
struct Bar
{
int a[5];
Bar() : a{1,2,3,4,5} {} // initialization in constructor initialization list
};
Or using an std::array:
struct Foo
{
std::array<int,5> a = {{1,2,3,4,5}}; // initialization at point of declaration
};
struct Bar
{
std::array<int,5> a;
Bar() : a{{1,2,3,4,5}} {} // initialization in constructor initialization list
};
If you can use C++11, there is support for uniform initialization which allows you to assign brace-enclosed lists of values in more contexts than the special case in C.
I mean: I've a bunch of various structures/classes and all this a splendor shall be initialized with known in advance values. Those structures/classes will never be used other way except the preinitialized one, so there is no any need for constructor -- it's just a waste of extra memory, extra CPU cycles in program, and extra space in source code.
If you have access to a C++11 compiler, you can mark your constructors as constexpr to have them run at compile time. The benefit of this is that way down the road you can still construct your objects at runtime. e.g.
struct Point2D {
constexpr Point2D(int x, int y) : x_{x}, y_{y} {}
int x_, y_;
};
And now you can use Point2D's constructor to initialize it at compile time, instead of runtime:
Point2D p{3, 4}; // no runtime overhead.
Structures and classes can be initialized, in limited circumstances.
struct splendor {
int i, j;
char *name;
};
splendor iforus = { 1, 2, "Extra!" };
Additionally, if you never need the name of the type of the structure:
struct {
int k;
float q;
} anon_e_mouse = { 1, 2.3 };
You can just initialize the members at the point of declaration:
struct Foo
{
int i = 42;
double x = 3.1416;
std::string name = "John Doe";
};
This will set up the default values for all instances:
Foo f;
std::cout << f.i << std::endl; // prints 42
Note that this does not work with C++03, it requires C++11 support.
If a class (or struct) doesn't have a constructor, you can initialize it like so:
MyClass a = MyClass();
or
MyClass * b = new MyClass();
This is called value initialization and it usually amounts to zero-initialization.
C++11 gives you initializer_list.
#include <iostream>
struct s
{
int i;
};
int main() {
s s1={666};
s s2={42};
std::cout<<s1.i<<" "<<s2.i<<std::endl;
return 0;
}
You can also do in-class initialization for member.
#include <iostream>
struct s
{
int i=0;
};
int main() {
s s1; //s1.i = 0
//s s2={42}; //fails
std::cout<<s1.i<<" "<<std::endl;
return 0;
}
But you cant do bot at the same time.
It sounds like you are trying to implement the Singleton Pattern. When you do that, you still need a constructor (in fact, if you want to force it to be a singleton, you have to declare the default constructor as private).
class MySingleton
{
private:
// my data
MySingleton() { /* initialize my data */ }
public:
static MySingleton& GetInstance()
{
static MySingleton instance;
return instance;
}
// other functions
};
I have a class that contains an array. I want this array to be set at the length of a constant:
// Entities.h
class Entities
{
private:
const int maxLimit;
int objects[maxLimit];
int currentUsage;
public:
Entities();
bool addObject(int identifier);
void showStructure();
};
The main problem I'm having is with the constructor. I thought:
// Entities.cpp
Entities::Entities() : maxLimit(50)
{
currentUsage = 0;
cout << "Entities constructed with max of 50" << endl;
}
would have been sufficient...but not so. I don't know if I can use the initialiser list for array initialisation.
How can I initialise the objects array using the maxLimit const? I'm relatively new to classes in C++ but I have experience with Java. I'm mainly testing out this phenomenon of 'constness'.
The array must have a constant length. I mean a length that is the same for all objects of that class. That is because the compiler has to know the size of each object, and it must be the same for all objects of that particular class. So, the following would do it:
class Entities
{
private:
static const int maxLimit = 50;
int objects[maxLimit];
int currentUsage;
public:
Entities();
bool addObject(int identifier);
void showStructure();
};
And in the cpp file:
const int Entities::maxLimit;
I prefer to use an enumeration for that, because i won't have to define the static in the cpp file then:
class Entities
{
private:
enum { maxLimit = 50 };
int objects[maxLimit];
int currentUsage;
public:
Entities();
bool addObject(int identifier);
void showStructure();
};
If you want to have a per-object size of the array, then you can use a dynamic array. vector is such one:
class Entities
{
private:
const int maxLimit;
std::vector<int> objects;
int currentUsage;
public:
Entities();
bool addObject(int identifier);
void showStructure();
};
// Entities.cpp
Entities::Entities(int limit)
: maxLimit(limit), objects(limit), currentUsage(0)
{
cout << "Entities constructed with max of 50" << endl;
}
Best is to do as much initialization in the initialization list as possible.
You can use template argument if you need to set array size at compile time:
template<size_t maxLimit>
class Entities
{
int objects[maxLimit];
public:
Entities() {}
...
};
Entities<1000> inst;
to dynamically allocate the memory you may need to use the 'new' keyword like
objects would be defined like:
int * objects;
inside the constructor you would do:
objects = new int [maxLimit];
edit:
forgot to mention, you'll need to deallocate the array when you're done, probably in the destructor of the class.
delete[] objects;
const ints have to be initialized at declaration. If you don't know the value that it has to be at the time of declaration, you're going to have to adopt a different strategy.
You'll need to create the array in the constructor, while keeping a pointer outside. Is this what you want to do?
In your class :
private:
int maxLimit;
int* objects;
And outside:
Entities::Entities() : maxLimit(50)
{
currentUsage = 0;
cout << "Entities constructed with max of 50" << endl;
objects = new int[maxLimit];
}
Entities::~Entities()
{
delete [] objects;
}
If all objects have the same length, then length can be static. This makes it a constant integral expression allowed as an array bound:
class Entities
{
private:
static const int maxLimit = 50;
int objects[maxLimit];
int currentUsage;
//...
};
Remember that sizeof(Entities) is a valid expression. Each Entities object has that same size.
Use std::vector and you get the expected behaviour. No need to worry about pointers, copies, etc
#include <vector>
class Entities
{
private:
const int limit;
std::vector<int> objects;
public:
Entities(int a_limit)
: limit(a_limit), objects(a_limit)
{ }
void addObject(int identifier)
{
if (objects.size() == limit)
throw whatever;
objects.push_back(identifier);
}
};