beginner question about arrays in structs in C++ - c++

I would like to create a struct and use it inside an other struct as an array. My problem is that I don't know how big array I would like to allocate, I will only know once I am in a function. I mean I would like to use [] instead of a pre-determined constant, like 10000.
I think if you look at my code it would be self-explanatory. Can you help me how to make this code work? Moreover it would help me a lot if you could tell me what is the name of the topic I am asking about (is it dynamic arrays?) and that where can I find articles/tutorials about this topic.
Here is the code with my broken way of thinking about arrays in structs.
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe keyframes[];
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
my_file.keyframes = new keyframe[my_file.num_keyframes];
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}

Use a std::vector.
struct keyframe_file {
const int num_views;
const int num_keyframes;
std::vector<keyframe> keyframes;
};
int main() {
keyframe_file frame;
frame.keyframes.resize(...);
}

If it suits your purpose, an STL container (std::vector) is easily one of the best options - the less memory management you have to worry about, the better.
In any case, look at the struct definition Nawaz posted above - that's exactly how it should be. Dynamic arrays in C++ are simply pointers. You have, however, allocated the memory properly in your code, but you haven't freed it (so it's leaking). Since you allocated with new [] you will need to
delete [] my_file.keyframes;
in order to free the memory properly.
Resizing is another issue: with a smart implementation, array resizing can be an amortized O(1) operation which is nice. When you resize, it will always take you O(n) since you need to copy all the elements into a new array of different size, but if you do it half as much, it becomes O(1). That is, double the array each time you need to resize. Here is a very quick example
void resize()
{
if(numOfElementsInArray == sizeOfArray)
{
ArrayType * arr = new ArrayType[sizeOfArray*2]; // Allocate a double size array
for(int i=0;i<sizeOfArray;++i)
currentArray[i] = arr[i];
delete [] currentArray; // Free memory in old array
currentArray = arr; // Set the array to our new one
sizeOfArray *= 2; // Double the size
}
}
NOTE: The example above does not take into account space complexity; that said, if you have 5000 elements, and remove all but 5, this method with not shrink it (which is probably what you will want to do for all practical purposes)

Your code appears to be almost correct, except for two things:
keyframes needs to be a keyframe* rather than a keyframe[]
You forgot to delete the memory you allocated

That is incomplete type. In C++, array must be provided with size, and the size must be known at compile time itself.
You're using new, with which you should be using pointer.
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
But std::vector<keyframe> is still a better choice, as #DeadMG already suggested.
By the way, the first two members are const in the struct, that means, they cannot be assigned value, as you're doing in your code. They must be initialized with values you want them to hold. That implies, now with vector, you've to include a constructor, to initialize the struct, as the struct is no more a POD.
struct keyframe_file {
const int num_views; //const member
const int num_keyframes; //const member
std::vector<keyframe> keyframes;
keyframe_file(int nviews, int nkeyframes)
: num_views(nviews), num_keyframes(nkeyframes), keyframes(nkeyframes){}
};
keyframe_file my_file(1,6); //done!

The suggested "Vector" is they safest way to do it.
But if it is only about making your code work (without resizing and stuff) the following should be working:
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file = {1, 6}; // initialization needed bcause of 'const int'
my_file.keyframes = new keyframe[my_file.num_keyframes];
for (int i = 0; i < my_file.num_keyframes; i++)
{
my_file.keyframes[i].a = true;
my_file.keyframes[i].b = 5 + i;
my_file.keyframes[i].c = 9 - i;
}
return 0;
}
somewhere in your code, when you are done using the array you have to call delete [] my_file.keyframes; as already mentioned.

There's a basic rule when using dynamic arrays in c++, especially when using it inside structs or classes, and it's to delete what you no longer need.
If you want to make your struct dynamic, it's easy, just replace the [] with * and the array will become dynamic, but it's not over yet, there is a lot of work.
You have to construct the array and destory it, and destoroying it is possible and useful noly with destructors, like this:
struct keyframe_file
{
const int num_views;
const int num_keyframes;
keyframe* keyframes;
~keyframe_file() // this is the destructor
{
delete[] keyframes;
}
};
Yet even that code isn't going to work at all, since you are assigning values to constants in variable my_file after creating it, it's illegal in c++, you should then use classes instead.
Using classes with dynamic arrays is very easy and interesting and makes your code very good, you don't have to know too much to do that, just learn what is a constructor, an initializer, destructor, private and public and go on with the following code:
#include <iostream>
using namespace std;
struct keyframe
{
bool a;
int b,c;
};
class keyframe_file
{
public:
keyframe_file(int NV, int NKF):num_keyframes(NKF),num_views(NV)
{
keyframes = new keyframe[num_keyframes];
}
~keyframe_file()
{
delete[] keyframes;
}
private:
const int num_views;
const int num_keyframes;
keyframe* keyframes;
};
int main()
{
keyframe_file my_file(1,6);
return 0;
}
This code works very well, it allows you to assign value to the constants num_views and num_keyframes for one time when creating the object (variable) my_file.
Remember, you are a C++ programmer, be proud of that, and use classes instead of structs and dynamic arrays instead of static ones.
Hope that's useful.

Use pointers and apply to your structure!
int *p;
p = new int;
#include <iostream>
using namespace std;
struct keyframe {
bool a;
int b;
int c;
};
struct keyframe_file {
const int num_views;
const int num_keyframes;
keyframe *keyframes;
};
int main() {
keyframe_file my_file;
my_file.num_views = 1;
my_file.num_keyframes = 6;
for (int i = 0; i < my_file.num_keyframes; i++){
my_file.keyframes = new keyframe; //<---
}
my_file.keyframes[0].a = true;
my_file.keyframes[0].b = 5;
my_file.keyframes[0].c = 9;
return 0;
}

Related

Organising C++ code

I am looking for some advice on how to organise my C++ code.
I have an int array, side, that I would like to be static in the sense that its value is kept constant between calls. This is because my function foo(), will modify the array side recursively and so I don't want copies to be made of side. Furthermore, the size of side can only be determined at compile time from the size of a vector that is passed into the function bar().
I have thought of the following structure to layout such a problem.
I keep a global int pointer, side, which I can then use to point to the address of my int array and then use the pointer *side within foo to do my modifications.
Please can you give me advise on the layout and organisation of this code? I am quite new to C++ so would appreciate any advice on the below structure.
#include <iostream>
#include <vector>
using namespace std;
int *side;
class A {
public:
int foo(bool);
int bar(vector<int>);
void set_n(int n){ class_n = n;};
private:
int class_n;
};
int A::foo(bool fl)
{
int n = class_n;
for(int i = 0; i < n; i++) {
// modify side[] and then recursively call foo
}
return 0;
}
int A::bar(vector<int> t)
{
int size = t.size();
set_n(size);
int a = foo(true);
int *side_local = new int[size];
for(int i = 0; i < size; i++) {
side_local[i] = 0;
}
side = side_local;
return 0;
}
int main()
{
A a;
vector<int> t = {1, 2, 3};
a.bar(t);
return 0;
}
A recursive call can pass a pointer to itself:
void foo(int *pList)
{
foo(pList); // recursive
}
the same list is then being worked on.
That being said, since foo is inside a class you wouldn't need a global either, but a member variable.
class A
{
int *pMemberList;
...
void foo();
}
now foo can see pMemberList all the time.
BUT ... passing it is probably a better option as in the future your class might house 2 lists that you want to do foo on.

Why won't this work? C++

I've recently started learning the basics of C++ by going through the book written on the language by Bjarne Stroustrup, and I've ran into a problem at the section where he goes over creating structures using Vector.
The error produced says that the variable or field 'vector_init' declared void,
'Vector' was not declared in this scope, 'v' was not declared in this scope, and expected primary-expression before 'int'
using namespace std;
int main(int argc, char const *argv[])
{
struct Vector {
int sz; // number of elements
double* elem; // pointer to elements
};
Vector my_first_vector;
return 0;
}
void vector_init(Vector& v, int s)
{
v.elem = new double[s]; // allocate an array of s doubles
v.sz = s;
}
The error message means exactly what it says; you've declared the struct Vector within the scope of main. Outside of main, no other functions know what Vector is. To fix this, move your definition of struct Vector to outside the main block.
You should move :
struct Vector {
int sz; // number of elements
double* elem; // pointer to elements
};
outside and above main
There are a few problems with your code... below is a fix that allows it to compile: you need to declare the struct Vector outside the main.
using namespace std; // <~ this is bad practice. Try to not use it (or minimize its scope)
struct Vector {
int sz; // number of elements
double* elem; // pointer to elements
};
int main(int argc, char const *argv[])
{
Vector my_first_vector;
return 0;
}
void vector_init(Vector& v, int s)
{
v.elem = new double[s]; // allocate an array of s doubles (also leaks memory)
v.sz = s;
}
I hope you plan to write a vector_clear method which will delete [] v.elem. Otherwise your program is going to leak memory.

How do I point to multi-dimensional array values?

I need some help on multi-dimensional arrays... I cannot find out how to assign a value to an array in a void task, that was created in main.
i tried to find help all over the place, but the longer i keep reading the less i understand
Please help
void addValue(a,b)
{
//somehow assign value to a[2][6] using pointers and such
void main()
{
int dest[7][7] = { 0 };
int a = 2;
int b = 6;
addValue(a,b);
}
Like this:
void addValue( int (*dest)[7], int a, int b )
{
dest[2][6] = 12;
}
int main()
{
int dest[7][7] = { 0 };
addValue(dest, a, b);
}
Consider using std::array instead of C-style arrays; the latter are an anachronism in C++. You can make the 7 a template parameter in addValue if you want to support other dimensions of array.

How to avoid returning handles to object internals - Item 28 Effective C++

Item 28 of Effective C++ says avoid returning "handles" to object internals. This question shows how to design your code to do exactly that by thinking about encapsulation in order to avoid accidentally exposing the internals of your class.
My example involves a data array and since memory is an issue I'd like to avoid using std::vector (and the Boost library).
Using an array here's a very simplified version of my code:
class Foo {
public:
Foo(int size) : data_(new int[size]) {
// Populate with data just for the example
for(int i = 0; i < size; i++) {
data_[i] = i;
}
}
// I know that this isn't good practice
int* const get_data() const {
return data_;
}
~Foo() {
delete[] data_;
}
private:
int* data_;
};
int main(void) {
Foo* foo = new Foo(10);
int* const data = foo->get_data();
delete foo;
// data now dangles which is bad!
return 0;
}
I understand that using const with get_data() doesn't make it safe. If I was using a vector I could copy it like the example question above, but since I'd like to avoid this I was wondering how best to design my class to avoid this potentially dangerous situation?
Programming and software design is a constant "choice of one thing over another". If you REALLY can't afford using std::vector, and you need to expose data to the client-code using your class, then so be it. Document why it is so, and make sure that it's reviewed over time - it may be that when your new model of hardware that has 8MB of RAM instead of 2MB will be able to use the extra 4 bytes that a vector takes over your plain pointer.
Or write an accessor function:
int& Foo::operator[](int pos)
{
// Add checks here to ensure `pos` is in range?
return data[pos];
}
Now you don't have to return the pointer at all...
The one way in your situation is to use smart pointers. I'd prefere shared_ptr. Here's how you can modify your class to avoid problems you raise:
class Foo {
public:
Foo(int size) : data_(new int[size]) {
// Populate with data just for the example
for(int i = 0; i < size; i++) {
data_[i] = i;
}
}
// I know that this isn't good practice
std::shared_ptr<int> const get_data() const {
return data_;
}
~Foo() {
//delete[] data_;
}
private:
std::shared_ptr<int> data_;
};
int main(void) {
Foo* foo = new Foo(10);
std::shared_ptr<int> data = foo->get_data();
delete foo;
// data still good )) // --now dangles which is bad!--
return 0;
}
There are plenty of cases where returning pointers is perfectly acceptable, even the array was actually contained in std::vector; e.g. using external APIs and when copying data is not appreciated.
I don't see the danger since you're not programming for monkeys. User of the class ought know. But I added function to query the size of the data. That is for safety.
extern "C"{
void foobar( const int *data, unsigned int size );
}
class Foo {
public:
Foo(unsigned int size) : size_(size), data_(new int[size]) {
// Populate with data just for the example
for(unsigned int i = 0; i < size; i++) {
data_[i] = i;
}
}
unsigned int get_size() const{return size_;}
int* const get_data() const {
return data_;
}
~Foo() {
delete[] data_;
}
private:
int* data_;
unsigned int size_;
};
int main(void) {
Foo* foo = new Foo(10);
int* const data = foo->get_data();
foobar( data, foo->get_size() );
delete foo;
return 0;
}
considering even the standard library has get_native_handle() on classes like std::thread I wonder who between the standard library or EC++ was wrong!
Effective C++ is a set of guidelines you simply can't apply them all in any context. It's a "moral" book. Don't treat it as "legal". If you are required to expose the data just do it.
After all who deletes a pointer to your internal data (after getting it through a getter) is also doing a "bad thing", since he's acting destructively on something does not belong to him.
If you really wish to avoid using std::vector, you can implement approach similar to one used by some winapi functions.
size_t get_data(int* data_ptr, size_t& buffer_size)
{
if(buffer_size < sizeof (data_)
{
buffer_size = sizeof(data);
return 0;
}
//You could you memcpy for ints here
for(int i = 0; i < size; i++) {
data_ptr[i] = i;
}
return sizof(data_);
}
Thus requiring caller to provide memory to store data and care about allocations of that memory.
Thru it should be reinvention of what std::vector already would do with much less safety.
Also you should check Rule of three to avoid problems when you will start using your class more extensively.

initialize a const array in a class initializer in C++

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.