Can class member arrays / std::arrays be replaced? - c++

New to C++, looking to replicate some functionality available in C# involving replacing an object array member with a newly constructed array.
class Car {
int id;
Car() {}
};
class Garage {
Car cars[1];
Garage() {}
void addCars(Car crs[]) {
//...do update here
}
};
In C# I could do something like:
addCars(Car[] crs){
Car[] temp = new Car[cars.Length + crs.Length];
for(int i = 0; i < cars.length; i++){
temp[i] = cars[i];
}
for(int i = 0; i < crs.Length; i++){
temp[i + cars.Length] = crs[i];
}
cars = temp;
}
Or Array.Resize, Array.Copy.
Can I declare an array and replace an existing object instance member array?
If this isn't possible: How practical are arrays in C++? I can see something like Excel utilising them (if they aren't modifiable) but it seems like it would be really limited. I can see why memory allocation might constrain this but obviously I'm from the easier side of the C fence.
Thanks.

As an example, here would be some sort of C++ equivalent to your example. It probably has some vague semblance to the C# equivalent.
#include <initializer_list>
#include <iostream>
#include <ostream>
#include <vector>
using std::vector;
using std::cout;
using std::endl;
using std::ostream;
using std::initializer_list;
struct Car {
int id;
Car(int newId) : id{newId} {}
};
ostream& operator<<(ostream& o, Car const& car) {
o << car.id;
return o;
}
struct Garage {
vector<Car> cars;
Garage() {}
void addCars(initializer_list<Car> l) {
cars.insert(cars.end(), l.begin(), l.end());
}
};
ostream& operator<<(ostream& o, Garage const& garage) {
char const* sep = "";
for (auto const& car : garage.cars) {
o << sep << car;
sep = ", ";
}
return o;
}
int main() {
Garage garage;
garage.addCars({7, 8, 99, 1000});
cout << garage << endl;
return 0;
}

Can I declare an array and replace an existing object instance member array?
No, std::array and type[] array sizes are known at compile time. If the new array has the same size as the existing array, a copy is needed (via e.g., memcpy)
You could theoretically use a pointer instead, e.g.
Car cars* = nullptr;
// ...
cars = new Car[size];
// ...
delete[] cars;
However, this puts the burden of memory tracking on you (I had to manually call delete[]). Instead, use a std::vector, which wraps up all that logic for you.
std::vector<Car> cars;
Car c;
// ...
cars.push_back(c);
How practical are arrays in C++?
Quite practical. A lot of high performance computing relies on arrays whose sizes are known at compile time for performance reasons.

The C++ arrays and std::array are fixed size at compile time. Their size can't change at runtime. You can copy an std::array onto another std::array ("replace"). But you can't do so for the C++ build-in arrays: these need to be copied element by element for example with std::copy().
If you need to dynamically resize your container, you should consider std::vector instead. These are much more flexible. And you can of course copy or move them as a whole.

Related

Returning 2d array of pointers in c++

I have a class and another class with class member of 2d array from the first class type.
and I need a function that returns that class member.
class Piece
{
// something is implemented here/
};
class Board
{
private:
Piece* _pieces[8][8];
public:
Piece*** getPieces()
{
return _pieces;
}
}
but that's not working.
This is a quick version of your class I made to allow the passing of the 2d array to work.
class Board
{
private:
Piece ** _pieces = new Piece*[8];
public:
Board()
{
for(int i = 0; i<8; i++)
_pieces[i] = new Piece[8];
}
Piece** getPieces()
{
return _pieces;
}
~Board()
{
for(int i = 0; i<8; i++) delete [] _pieces[i];
delete [] _pieces;
}
};
You could std::array to create 2D array of pointers if you have access to C++11/14/17, it's a lot cleaner and expressive than using the build in array that decay to a ptr.
What follows is an example of how you create and return from Booard a 8x8 2D array of pointers to Pieces.
#include <array>
class Piece
{
// something is implemented here/
};
using Pieces=std::array<std::array<Piece*,8>,8>;
class Board
{
private:
Pieces _pieces;
public:
const Pieces& getPieces()
{
return _pieces;
}
};
As suggested by #Galik in comment, you should use std::arrays here, because the sizes are constant expressions.
It is not really mandated by the standard, but for common implementations, a std::array<std::array<T,i>,j> does have a true T[i][j] 2D array as underlying data - said differently, consecutive rows use adjacent memory. std::vector on another hand acts more as an array of pointers and data of consecutive rows are generally not adjacent in memory.
Code could become:
class Board
{
private:
std::array<std::array<Piece*, 8>, 8> _pieces;
public:
std::array<std::array<Piece*, 8>, 8>& getPieces()
{
return _pieces;
}
}
But this is still poor design, because it unnecessarily exposes the underlying implementation, so you really should think twice on what should be the public methods for the Board class.
for example,
int a[3][6];
int **p=a; // it's wrong
You should use pointer like this:
int (*p)[6];
p=a;

passing an array into a class function from another class's constructor

Sorry for the confusing title, basically I have created two classes, one is an object, and the other being a box that contains an array of such objects. so what I want to do is create a function/constructor inside the object class that takes in an array of ints and stores them inside the box. I want to be able to call this function through the box class constructor to initialize these objects. So ive tried something like below but it isnt working at all, since only the first value of the array gets passed through. What am I doing wrong?
#include <iostream>
#include <string>
class object{
string objectName;
int values[];
public:
void createObject(int[]);
}
class Box{
object objects[100];
public:
Box();
}
Box::Box (void){
int array1[2];
int array2[15];
object[1].createObject(array1);
object[2].createObject(array2);
}
Object::Object(int Values[]){
values = Values;
}
You should really use std::vector. The problem with arrays is that they decay to pointers when passed as arguments to functions. As a consequence, If you want to store a private copy of the elements you are forced to use heap-allocated objects and consequently do memory management by hand (with all the pain it causes).
It is much better to rely on data members that permit applying the rule of zero.
Here's a tentative solution:
#include <iostream>
#include <string>
#include <vector>
class object {
public:
object(std::vector<int> const& v, std::string const& object_name): v_(v.begin(), v.end()), object_name_(object_name) {}
private:
std::vector<int> v_;
std::string object_name_;
};
class box {
public:
box(std::vector<object> const& objects): objects_(objects) {};
private:
std::vector<object> objects_;
};
I recommend you instead use a std::vector. Arrays don't really work well being passed to functions. When you define Object::Object(int Values[]) you are simply passing the first element of this array by value. If you were to use vectors, the function would look like this:
Object::Object(std::vector<int> &Values):
values(Values)
{
}
The problem with the code is in your thinking on what the array is. In C++, all an array is, is a memory pointer. The language allows you to pass an index into the array pointer to access whatever chunk of data lives at that index.
Whenever you pass arrays between functions or classes, pass the array name only. It will be interpreted as a pointer, and won't copy any data. When you do this, you must also pass the length of the array.
Granted, most people stick with vector<> because it's easier, takes care of memory leaks (mostly) and is VERY efficient. But I like doing it myself. It's good for you. I would try:
#include <iostream>
#include <string>
class Object
{
string _objectName;
int *_values;
int _myLength;
Object();
~Object();
void createObject(int *pValues, int arrLength);
}
class Box
{
_Object objects[100];
Box();
}
Box::Box(void) {
int array1[2];
int array2[15];
object[1].createObject(array1, 2);
object[2].createObject(array2, 15);
}
Object::Object() {
_values = null_ptr;
_myLength = 0;
}
Object::~Object() {
delete[] _values;
}
void Object::createObject(int *pvalues, int arrLength) {
_myLength = arrLength;
_values = new int[_myLength];
for(int ndx=0; ndx<arrLength; ndx++) {
_values[ndx] = pvalues[ndx];
}
}
-CAUTION-
I just adapted your code you provided, and added some conventions. There are a couple places in the code where I'm not sure what the purpose is, but there you go. This should give you a good head start.

C++ - Return multidimensional array from function

I am writing a code for Cellular Automata and I need an evolution function to calculate the state of the automata after a time step.
I choose to call this function evol, to test it I created an elementary function in C++. Unfortunately it does not compile since the compiler cannot understand that I need it to return an array. Here is the code :
#include <iostream>
#include <cmath>
#include <vector>
#include <string>
using namespace std;
const int N = 51; // Size of the grid; two columns/rows are added at the beginning and the end of the array (no evolution of the CA on the boundaries)
class Cell{
//defining whats a cell here
};
void showCA(Cell CA[N+2][N+2]){
//function to print the CA grid in the terminal
}
Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){
return CA;
}
int main()
{
// Initialisation
cout << "Initialisation" << endl;
static Cell CA[N+2][N+2];
// some code here to initialize properly the Cell array.
showCA(CA);
CA = evol(CA);
showCA(CA);
return 0;
}
The compiler returns this error :
error: expected unqualified-id
Cell[N+2][N+2] evol(Cell CA[N+2][N+2]){
Any idea on how I should implement this ?
You cannot return arrays from functions:
ยง 8.3.5/8
Functions shall not have a return type of type array or function, although they may have a return type of type pointer or reference to such things.
If you are wishing to return raw, C-style arrays from functions, then you have to use a reference or pointer. For example, here's how it is done using a reference (you can do the same using a pointer by replacing & with *):
Cell (&evol(Cell (&CA)[N+2][N+2]))[N+2][N+2];
However, this is very unintuitive and hard to read. If your compiler supports the latest standard (C++11) the return type can be cleaned up using a trailing return type:
auto evol(Cell (&CA)[N+2][N+2]) -> Cell(&)[N+2][N+2];
But again, this is probably still harder to read.
C++11 facilitates the handling of C-style arrays with the container std::array<>. Non-C++11 code should use std::vector<>:
using Cells = std::array<std::array<Cell, N+2>, N+2>;
Cells const& evol(Cells const& CA);
You can use
typedef std::vector<std::vector<Cell>> CellArray;
CellArray Cells(N+2); // resize main dimension
for (size_t i=0; i<N+2; i++)
Cells[i].resize(N+2); // resize all cells of main dimension
to hold your cell array, but you also need to add a copy constructor and operator= in Cell class
class Cell {
public:
Cell() { ... default ctor code here ... }
Cell(const Cell &c) { *this = c; }
Cell &operator=(const Cell&c)
{
if (this != &c)
{
... copy data from c members to this members here ...
}
return *this;
}
};
Your evol function then can return a CellArray:
CellArray evol(CellArray &c)
{
CellArray r;
... do some calculations with c and r ...
return r;
}
once you have declared a variable using the array syntax like you have:
Cell CA[N+2][N+2];
you cannot assign CA to be something else. You can only assign values to its contents. Hence,
CA = evol(CA);
is wrong.
You can do the following:
Cell (*CA2)[N+2] = evol(CA);
As the number of elements seems to be fixed, I suggest you use the std::array container:
const int N = 51;
typedef std::array<std::array<Cell,N+2>, N+2> datatype;
You can then use this type as a return type:
datatype Evol( const datatype& d );
You can access elements just as if it was a "C" array:
datatype d;
Cell c;
d[10][20] = c;
I would strongly suggest encapsulate your array into a class. You cannot return an array, but you can return an object that contains an array.

Allocating an array of a class c++

How would I go about allocating an array of a class without constructing the class, so I could fill up the array later?
I was originally trying to use
Myclass * array = new Myclass[N];
But it tries to construct Myclass to N.
First just declare it without allocating
Myclass * array[N];
when you need it
for(int i=0;i<N;i++){
array[i] = new Myclass(/*params*/);
}
But consider using std::vector/std::list if you must not have to manage memory yourself.
If you really want to do that, (not sure why), you could try
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{ cout << "helo" << endl; }
};
int main(int argc, char *argv[])
{
int size = 4;
// Here is the trick, pointer to pointer.
MyClass **vec = new MyClass *[size];
cout << "before" << endl;
for (int i = 0; i < 4; ++i)
vec[i] = new MyClass;
// remember to free the vec
return 0;
}
Someone suggested placement new, so here it goes:
// allocate space
std::vector<unsigned char> mybuffer(N * sizeof(Myclass));
Myclass *array = reinterpret_cast<Myclass *>(&mybuffer[0]);
// when you're ready to use it
new( &array[0] ) Myclass(2);
new( &array[1] ) Myclass(3);
// etc...
// when you're done with it
array[0].~Myclass();
array[1].~Myclass();
// etc....
Of course, it is undefined behaviour to use array[x] before you have new'd it, or after you called the destructor.
This is generally something you wouldn't use as a solution to a "normal" problem. Consider actually defining a default constructor that does nothing, and having a function you call later which enhances the objects above their default state.
If you can use C++11, the optimal solution for you is probably std::vector<MyClass> with emplace-base insertions:
class MyClass {
public:
MyClass(int a, bool b, char c); // some non-default constructor
MyClass(double d); // another constructor
void bar();
};
void foo(int n) {
std::vector<MyClass> mv;
mv.reserve(n); // not even needed but beneficial if you know the final size.
// emplace_back uses perfect forwarding to call any arbitrary constructor:
mv.emplace_back(2, false, 'a');
mv.emplace_back(3, true, 'b');
mv.emplace_back(3.1415926535);
// can iterate vector easily:
for (auto &i : mv) {
i.bar();
}
// everything destructed automatically when the collection falls of scope ...
}
This creates the values in the collection directly without a copy and defers any construction of elements until you are ready, unlike new[], which makes a bunch of default objects at array-creation time. It is generally better than placement new as well, since it doesn't leave open opportunities for missed destruction or destructing an invalid memory location as well as being just easier to read.
Alternatively, you may use boost::optional.
So in your case:
std::vector<boost::optional<Myclass>> array(N);

Determine array size in constructor initializer

In the code below I would like array to be defined as an array of size x when the Class constructor is called. How can I do that?
class Class
{
public:
int array[];
Class(int x) : ??? { }
}
You folks have so overcomplicated this. Of course you can do this in C++. It is fine for him to use a normal array for efficiency. A vector only makes sense if he doesn't know the final size of the array ahead of time, i.e., it needs to grow over time.
If you can know the array size one level higher in the chain, a templated class is the easiest, because there's no dynamic allocation and no chance of memory leaks:
template < int ARRAY_LEN > // you can even set to a default value here of C++'11
class MyClass
{
int array[ARRAY_LEN]; // Don't need to alloc or dealloc in structure! Works like you imagine!
}
// Then you set the length of each object where you declare the object, e.g.
MyClass<1024> instance; // But only works for constant values, i.e. known to compiler
If you can't know the length at the place you declare the object, or if you want to reuse the same object with different lengths, or you must accept an unknown length, then you need to allocate it in your constructor and free it in your destructor... (and in theory always check to make sure it worked...)
class MyClass
{
int *array;
MyClass(int len) { array = calloc(sizeof(int), len); assert(array); }
~MyClass() { free(array); array = NULL; } // DON'T FORGET TO FREE UP SPACE!
}
You can't initialize the size of an array with a non-const dimension that can't be calculated at compile time (at least not in current C++ standard, AFAIK).
I recommend using std::vector<int> instead of array. It provides array like syntax for most of the operations.
Use the new operator:
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
I don't think it can be done. At least not the way you want. You can't create a statically sized array (array[]) when the size comes from dynamic information (x).
You'll need to either store a pointer-to-int, and the size, and overload the copy constructor, assignment operator, and destructor to handle it, or use std::vector.
class Class
{
::std::vector<int> array;
Class(int x) : array(x) { }
};
Sorry for necroing this old thread.
There is actually a way to find out the size of the array compile-time. It goes something like this:
#include <cstdlib>
template<typename T>
class Class
{
T* _Buffer;
public:
template<size_t SIZE>
Class(T (&static_array)[SIZE])
{
_Buffer = (T*)malloc(sizeof(T) * SIZE);
memcpy(_Buffer, static_array, sizeof(T) * SIZE);
}
~Class()
{
if(_Buffer)
{
free(_Buffer);
_Buffer = NULL;
}
}
};
int main()
{
int int_array[32];
Class<int> c = Class<int>(int_array);
return 0;
}
Alternatively, if you hate to malloc / new, then you can create a size templated class instead. Though, I wouldn't really recommend it and the syntax is quite ugly.
#include <cstdio>
template<typename T, size_t SIZE>
class Class
{
private:
T _Array[sz];
public:
Class(T (&static_array)[SIZE])
{
memcpy(_Array, static_array, sizeof(T) * SIZE);
}
};
int main()
{
char int_array[32];
Class<char, sizeof(int_array)> c = Class<char, sizeof(int_array)>(int_array);
return 0;
}
Anyways, I hope this was helpful :)
I had the same problem and I solved it this way
class example
{
int *array;
example (int size)
{
array = new int[size];
}
}
Don't you understand there is not need to use vector, if one wants to use arrays it's a matter of efficiency, e.g. less space, no copy time (in such case if handled properly there is not even need to delete the array within a destructor), etc. wichever reasons one has.
the correct answer is: (quoted)
class Class
{
int* array;
Class(int x) : array(new int[x]) {};
};
Do not try to force one to use non optimal alternatives or you'll be confusing unexperienced programmers
Instead of using a raw array, why not use a vector instead.
class SomeType {
vector<int> v;
SomeType(size_t x): v(x) {}
};
Using a vector will give you automatic leak protection in the face of an exception and many other benefits over a raw array.
Like already suggested, vector is a good choice for most cases.
Alternatively, if dynamic memory allocation is to be avoided and the maximum size is known at compile time, a custom allocator can be used together with std::vector or a library like the embedded template library can be used.
See here: https://www.etlcpp.com/home.html
Example class:
#include <etl/vector.h>
class TestDummyClass {
public:
TestDummyClass(size_t vectorSize) {
if(vectorSize < MAX_SIZE) {
testVector.resize(vectorSize);
}
}
private:
static constexpr uint8_t MAX_SIZE = 20;
etl::vector<int, MAX_SIZE> testVector;
uint8_t dummyMember = 0;
};
You can't do it in C++ - use a std::vector instead:
#include <vector>
struct A {
std::vector <int> vec;
A( int size ) : vec( size ) {
}
};
Declare your array as a pointer. You can initialize it in the initializer list later through through new.
Better to use vector for unknown size.
You might want to look at this question as well on variable length arrays.