How do I instantiate an array's size later? - c++

Let's say I have a base class called
Class Base {
public:
std::string array[];
};
The size the string array is not decided until another class extends it, what's the correct syntax for doing so?
EG, later on in a derived class
Derived::Derived() {
array[] = new array[40];
}

If you want to use a C-style array, the size must be fixed and known at compile-time. And even in that case, you could use the safer, zero-overhead std::array<> wrapper instead.
If the size of your container is not known at compile-time, then it is good practice to use std::vector (or std::deque in some cases, based on your requirements in terms of memory allocation) and avoid manual memory management through raw pointers, new[] and delete[]:
#include <string> // For std::string
#include <vector> // For std::vector
class Base {
public:
std::vector<std::string> myVector;
};
Besides, this design won't require any dedicated work in the constructor (and destructor) of Derived. If all that was done by Derived's default constructor was to allocate the array, now you can avoid explicitly defining a default constructor at all, and let the compiler generate one for you implicitly - same story for the destructor.
Also, I would discourage you from using names of standard container classes (like array) as names for your variables. Something like myArray (or myVector, as in my example above) are more appropriate choices.

You don't. Arrays in C++ are of compile-time fixed size. You cannot just resize them to your liking.
The bad way to do this using only language features is to actually have your member as an std::string*:
std::string* array;
And then dynamically allocate an array of std::strings, assigning the pointer to the first element to array:
Derived::Derived() {
array = new std::string[40];
}
The good way to do this is to use library features. The standard library provides container types for you to use. Try a std::vector<std::string>:
std::vector<std::string> array;
Which you could initialise to contain 40 strings like so:
Derived::Derived()
: array(40)
{ }

Why not use a std::vector<std::string> so that you don't have to worry about size. The container resizes automagically as new things are inserted into it.

Using a vector of string is normally better solution.
But this will work:
Class Base {
Public:
std::string *array;
};
Derived::Derived() {
array = new array[40];
}
I'd add:
Class Base {
Public:
std::string *arr;
Base():arr(nullptr){}
Base(sizr_t s):arr(new std::string[s]){}
~Base(){delete []arr;}
};
Derived::Derived():Base(40) { }
And you may need to write copy/move constructors and asignments. Derived dont have to know about very much.
Now compare with:
Class Base {
Public:
std::vector<std::string> arr;
Base(){}
Base(sizr_t s):arr(s){}
};
All other special functions: destructor, copy/move constructors and asignments are generated by compiler. And the constructor of Derived is still:
Derived::Derived():Base(40) { }
Also... you may want to make arr private or at least protected?

The correct syntax is
std::vector<std::string> array;

As well as the done-to-death heap allocation, you can size it statically as in:
template <int N>
class Base
{
public:
std::string array[N];
};
class Derived : Base<40>
{ ... }
Pros: simple, avoids (relatively slow) memory allocation at runtime and the hassles of cleanup (smart array pointer or otherwise). Cons: each instantiation of Base is a distinct type, which can lead to a little more bloat and less interoperability.

Related

How to make an object take and store an Array of arbitrary, but compile-time known size?

Background
For an embedded project, I want a class that takes a list of structs. This list is known at compile-time, so I shouldn't have to resort to dynamic memory allocation for this.
However, how do I make a struct/class that encapsulates this array without having to use its size as a template parameter?
Templates
My first idea was to do exactly that:
struct Point {
const uint16_t a;
const double b;
};
template<size_t n>
struct Profile {
Array<Point, n> points;
Profile(const Array<Point, n> &points) : points(points) {}
};
Here, Profile is the class that stores/encapsulates the array of points (the 2-member structs). n, the size of the array, is a template parameter.
I'm using this implementation of Array, similar to std::array, btw, because I don't have access to the STL on this embedded platform.
However, no I have another class that uses this Profile that now also has to be templated because Profile is templated with the size of the array:
template<size_t n>
class Runner {
private:
const Profile<n> profile;
public:
Runner(const Profile<n> &profile) : profile(profile) {};
void foo() {
for(auto point : profile.points) {
// do something
}
}
};
As can be seen, this Runner class operates on a Profile and iterates over it. Having to template Runner is not that much of an issue by itself, but this Runner in turn is used by another class in my project, because this other class calls Runner::foo(). Now I have to template that class as well! And classes that use that class, etc.
That's getting out of hand! What started with just one template parameter to specify the size, now propagates through my entire application. Therefore, I don't think this is a good solution.
Question
Is there a way to 'hide' the size of the array in Profile or Runner? Runner only needs to iterate over it, so the size should in principle only affect its implementation, not its public interface. How would I do that, though?
Also, can I avoid having to manually specify n at all, and just pass an array to Profile's constructor and let the compiler figure out how big it is? At compile-time, of course. I feel like this should be possible (given this array is known at compile-time), but I don't know how exactly.
Other approaches
Macros
I could write a macro like
#define n 12
and include that in both the Profile.h and the place where I instantiate a Profile. This feels dirty though, I and would like to avoid macros.
Vector
I could avoid this fuss by just using a std::vector (or equivalent) instead, but that is allocated at run-time on the heap, which I would like to avoid here since it shouldn't be necessary.
Is there a way to 'hide' the size of the array in Profile or Runner?
Yes. The solution is indirection. Instead of storing the object directly, you can point to it. You don't need to know the size of what you're pointing at.
A convenient solution is to point into dynamic storage (for example std::vector) because it allows you to "bind" the lifetime of the dynamically sized object to a member. That's not necessary in general, and you can use automatic storage instead. However, in that case you cannot bind the lifetime of the pointed object, and you must be very careful to not let the pointed object be destroyed before you stop using it.
The indirection can be done at whatever level you prefer. If you do it at the lowest level, you simply store the array outside of Profile. In fact, if all that profile does is contain an array, then you don't need a class for it. Use a generic span:
struct Runner {
span<const Point> profile;
void foo() {
for(auto point : profile) {
// do something
}
}
};
Point points[] {
// ... number of points doesn't matter
};
Runner runner {
.profile = points,
};
By span, I mean something like std::span. If you cannot use the standard library, then use another implementation. It's basically just a pointer and size, with convenient template constructor.
To clarify, you can pick any two, but you cannot have all three of these:
Lifetime of the array bound to the class (safe)
No compiletime constant size
No dynamic storage
1,2 (no 3) = std::vector, RAII
1,3 (no 2) = std::array, templates, no indirection
2,3 (no 1) = std::span, be careful with lifetimes
I'll expand on this comment:
The idea is that Runner takes Profiles no matter their size. Runner needs to iterate over it, but apart from that, its behaviour is always the same. The class using Runner and calling Runner::foo() doesn't need to know the size. The problem with templating Runner is that the class using Runner also needs to be templated, and the classes using that, etc.
This is only a problem when the class is using the templated Runner directly. It has more dependencies than it actually needs. If it doesn't need to know about the size of the array, then it should not know about the size of the array. If runtime polymorphism is an option you can add a base class that allows accessing the array elements, but doesn't need to know anything about the arrays size. The following is only a sketch:
#include <iostream>
struct RunnerInterface {
virtual int* begin() = 0;
virtual int* end() = 0;
virtual ~RunnerInterface(){}
};
template <unsigned size>
struct Runner : RunnerInterface {
int data[size];
int* begin() override { return data; }
int* end() override { return data+size; } // pointer one past the end if fine (it won't get dereferenced)
};
void foo(RunnerInterface& ri) {
for (auto it = ri.begin(); it != ri.end(); ++it){
*it = 42;
}
}
void bar(RunnerInterface& ri){
for (auto it = ri.begin(); it != ri.end(); ++it){
std::cout << *it;
}
}
int main() {
Runner<42> r;
foo(r);
bar(r);
}
Now if a class needs a Runner member, they store a std::unique_ptr<RunnerInterface> and only on construction you need to decide for the size of the array (though you still need to decide for the size somewhere).

How can I instantiate a class with statically declared arrays of different sizes?

I'd like to create a class with a statically declared array. I'd like to extend the class that basically changes the size of the array in the derived class. Everything else would stay the same.
namespace someNameSpace {
const uint8_t STATIC_ARRAY_SIZE = 50; // <-- change this value in a derived class?
class BaseClass {
private:
int some_array[STATIC_ARRAY_SIZE];
public:
void some_function_that_uses_above_array(){ ... };
}
}
Is there a way to do this without using templating? (I need the arrays to be allocated memory at compile time).
You can use template meta-programming for this:
namespace someNameSpace {
template <size_t STATIC_ARRAY_SIZE>
class BaseClass {
private:
int some_array[STATIC_ARRAY_SIZE];
public:
void some_function_that_uses_above_array(){ ... };
}
class Derived : public BaseClass<42> {
...
}
}
If you want to allocated at compile time, it is mean not dinamically allocated i think the solution you want still is template. At compile time for each different template parameter the compiler will generate a copy of class.
Example:
With #sturcotte06 code, if you declare in someplace BaseClass<10> or BaseClass<20>, for each parameter 10 and 20, the compiler will copy the code of class and apply the parameter like a #define.
In this link search for "PrintTwice function with int and double", there is a pratical example.
If you can't use template because of restrictions, i don't recommend but you can pass the array through constructor as a smart pointer, to avoid null reference is important check pointer on costructor and take a care on destructor.

std::vector of objects / pointers / smart pointers to pass objects (buss error: 10)?

I would like to ask a general advise. The code below fully compiles and roughly represents the structure of the code i deal with.
In a nutshell i want to pass a series of objects derived from the based class (Class1) and some other parameters from one place to another. More precisely, implement different child classes of the parent class, gather instances of those and pass for processing with parameters.
The question is, would you recommend to use a vector of objects or vector of pointers? I don't mind going for some new stuff from C++11 (std::unique_ptr, std::shared_ptr) if this is better/safer/less memory leaks/etc for some reason. I would really appreciate if someone could arguably advise on container for such a case and/or provide an example using C++11.
p/s/ here UncleBens said that using pointers could lead to memory leaks if/when exceptions are thrown. So maybe i should really use smart pointers for the task? How would this look?
p/p/s/ funny enough, the real life example gives me Bus error: 10 when i try to use those Class2 objects from std::vector< Container<d>*> / std::vector< Container<d>> . However, i'm not able to reproduce the error in a simple case...
#include <string>
#include <iostream>
#include <vector>
template<int dim>
class Class1 {
public:
Class1() {};
~Class1() {};
};
template<int dim>
class Class2 : public Class1<dim>
{
public:
Class2() :
Class1<dim>() {};
};
template <int dim>
class Container
{
public:
Container( Class1<dim> & f, int param1) : c1(f), param_(param1) {}
Class1<dim> & c1;
int param_;
};
static const int d = 2;
int main()
{
int p = 1;
Class2<d> c2;
std::vector< Container<d> *> p_list;
std::vector< Container<d> > list;
{
p_list.push_back ( new Container<d> ( c2,p ) );
}
std::cout<<"from pointers: "<<p_list[0]->param_<<std::endl;
{
list.push_back( Container<d> ( c2,p ) );
}
std::cout<<"from objects: "<<list[0].param_<<std::endl;
}
Firstly, the destructor of Class1 should be marked virtual, otherwise when an instance of a deriving class (Class2 for example) is destroyed, it's destructor wont be called correctly.
As for your question, the consequences of using a container of objects are:
The container might need to make copies of the objects, so you need to make sure there is a copy constructor (your class in the example gets the default one generated by the compiler). Copying objects can have a performance impact, and you need to properly define the semantics of the copy (is it deep or shallow, i.e. do you create a new copy of the class1 object, or just copy the reference).
You can't have any polymorphism, so you couldn't subclass Container and then put instances of the base and subclass in the same container.
Depending on the container, your objects will be contiguous in memory (this is the case for a vector) which can have performance benefits.
If you use a container of raw pointers, then the container only needs to copy pointers (faster) and you can add derived instances of the contained type. The downside is that you'll have to destroy the objects manually after use and as you mentioned, it's easy to leak memory.
shared_ptrs have similar benefits/downsides to raw pointers, but the key benefit is the the shared_ptr destroys the object for you when nothing is referencing it any more, this makes it less likely that you'll introduce memory leaks (but it's still not impossible to do so when exceptions are involved).
Given that your handing these objects over for further processing, I would say a shared_ptr based approach is a good option. The consequences of using shared ptrs over and above those of raw pointers are:
There can be a performance overhead, as in order to be thread safe, most shared_ptr implementations need to check/set locks (this might involve a system call to the OS).
you can still leak memory by introducing circular references between objects.
you'll have to use a compiler implementing C++11 or use external libraries (most people use boost).
An example using shared_ptrs would look something like this (not tested).
#include <string>
#include <iostream>
#include <vector>
template<int dim>
class Class1 {
public:
Class1() {};
virtual ~Class1() {};
};
template<int dim>
class Class2 : public Class1<dim>
{
public:
Class2() :
Class1<dim>() {};
};
template <int dim>
class Container
{
public:
Container( boost::shared_ptr<Class1<dim>> f, int param1) : c1(f), param_(param1) {}
boost::shared_ptr<Class1<dim>> c1;
int param_;
};
static const int d = 2;
int main()
{
int p = 1;
boost::shared_ptr<Class1<d>> c2 = boost::make_shared<Class2<d>>();
std::vector<boost::shared_ptr<Container<d>>> list;
list.push_back(boost::make_shared<Container<d>>(c2,p));
std::cout << "from objects: " << list[0]->param_ << std::endl;
}
In summary, if the code receiving the containers doesn't store refs to them anywhere, and you don't need polymorphism, then a container of objects is probably ok. If it is necessary for the code receiving the containers to store them somewhere, and/or you want polymorphic containers, use shared ptrs.

fixed size C-style arrays in class declarations

I've come across a bit of code which essentially looks like this:
#include<iostream>
// in a header file
class xxx{
public:
xxx() { xxx_[0]=0; xxx_[1]=0; xxx_[2]=0;}
double x0() const {return xxx_[0];}
private:
double xxx_[3]; // ???
};
// in the main.cpp
int main(){
xxx x;
std::cout<<x.x0()<<"\n";
}
The question is --- is declaring as a class member an array of fixed size is really allowed by the standard?
There is nothing wrong with the above code. It might not be the best way to write it, but there is nothing intrinsically wrong with it.
Yes, your class xxx may contain a fixed-size array as a member. It's allowed in C too.
The compiler, even when reading the header to use it, knows how big to make sizeof(xxx) as a result.
There is nothing wrong with declaring static array as a member of class:
class A
{
int a[3];
};
It is allowed.
Design-wise, this is often not ideal, though; arrays don't have such a nice interface as std::array has:
std::array<double,3> xxx_;
for (auto it : xxx_) {...}
xxx_.size()
std::transform (xxx_.begin(), xxx_.end(), ...);
etc. So if you find yourself using your (static sized) array as a container most of the time, you should replace it with std::array (which has no spatial overhead). If you need dynamic sized arrays, look at std::vector, which has a small overhead (size + capacity, however, with manual allocation, you must remember the size, too, so the only overhead is capacity).

Embedded C++: Initialization of an array member of a struct within a class, size omitted

Hello there and thanks in advance for any help on the following matter.
Edit: I forgot to add that this is on an embedded system with no access to STL features. My apologies for leaving this very important piece of information out. This is my first time coding in C++ extensively so I forgot to mention the obvious. I came back to add this fact and this question had already received some replies. Thank you all for such a quick response!
I am trying to initialize an array member of a struct that is in turn a public member of a C++ class. The array size is omitted in the struct. Here is an example:
// ClassA.h
Class A
{
public:
struct StructA
{
StructB structs[];
};
struct StructB
{
// stuff
};
ClassA();
//etc
};
// ClassB.h
ClassB: public ClassA
{
public:
StructA structA;
ClassB()
// etc
};
// ClassB.cpp
// What do I do here?
I tried:
StructA ClassB::structA.structs[] = { first, second, third }
without any luck. I'm relatively new to C++ so this one has stumped me.
I can add a size to the array member in StructA but I would rather not if
there is a legal way to handle this.
Thanks!
Arrays without a size aren't valid C++; they're a feature in C99, where they require some malloc magic to function. If you try to compile code using this feature with g++ -pedantic, you'll see that it emits:
$ g++ -Wall -pedantic test.cc
test.cc:5: error: ISO C++ forbids zero-size array 'foo'
I suggest you use std::vector instead, which has the same function as unsized arrays in C99 but is much safer:
std::vector<StructB> structs;
then add elements with push_back.
Since you code in c++ anyway, why not use:
std::vector<structA> mStruct; ...
mStruct.push_back(first); ...
std::vectors are quiet comfortable in comparison to c-array and less error prone.
In general, it's hard to create something that has a variable size in C or C++, without resorting to dynamic allocation, which you should try to avoid when using embedded systems.
I would suggest that you would create a plain array of things, and place a pointer to this inside your class. You can place the array in global scope, and the pointer does not have to know it's size.
In addition, by simply placing something in a class doesn't make it global. You must either make it a static member (meaning that there will be exactly one variable, regardless of how many objects of that particular class there is), or initialize it in the constructor.
For example:
class A
{
public:
struct B
{
char const * str;
};
// Constructor
A(A::B * beePointer)
: mB(beePointer)
{
}
// Data members
B * mB;
};
// Global array
A::B my_Bees[] = {"first", "second", "third"};
A my_a(my_Bees);
Of course, in this solution, you can't add more elements to the end of the array, as it is allocated once and for all.
You can't have unsized arrays in C++. Since you don't have access to vector:
If you know the maximum number of items you'll never need, just size your array to that value.
If you don't know the maximum number of items you'll never need, you'll have to dynamically manage your memory in some way. You can try new/delete by default but you may need to create your own memory pool if the defaults aren't performant enough.
If the very last line of your post indicates that you only ever need one copy of the array in the whole program, AND that you know what values to initialize to at compile time you can use a static class member. Your sample code had multiple problems so I had a hard time guessing what you wanted.
A sample of how the static would look though:
// ClassA.h
class ClassA
{
public:
struct StructB
{
// stuff
};
struct StructA
{
static StructB structs[];
};
ClassA();
//etc
};
// ClassB.h
class ClassB: public ClassA
{
public:
StructA structA;
ClassB() { }
// etc
};
// ClassB.cpp
ClassA::StructB first, second, third;
// What do I do here?
ClassA::StructB ClassA::StructA::structs[] = { first, second, third };
int main()
{
return 0;
}