Declare array of fixed length in nested classes
Asked Answered
M

4

2

I have a class A, which has a nested class B. Class A, will create n(run time parameter) instances of class B.

In the constructor of A, after computations that need to be made at run time, I compute a size, let's say s.

Now, every class B, will hold an array of size s.

However, I am not allowed to use .cpp files and all the work must be done in header files.

This means, as far as I understand, that I can not use these approach (with static):

class B {

static const int s;
int a[s];

};

So, I decided to use enum, but I couldn't make it work (even with enum class of C++11). The idea is that you do something like:

class B {

enum { s = 50 };
int a[s];

};

but I do not know the s before run time.

Of course, I could go with an std::vector or with dynamic allocation.

But since:

1)I need only the functionality of the old good arrays (discards vector)

2)I know before constructing the instances of B, the size of the array (discards dynamic allocation)

About std::dynarray discussed below:

Unfortunately not in C++14, but in array TS or C++17. Source, credits to manlio.

Discard is however a heavy word. I mean, I have heard that automatic allocation is faster, but dynamic allocation lets you allocate more space. Moreover, vectors, in the release mode, are doing not that bad in comparison with the arrays.

Madalene answered 6/5, 2014 at 13:36 Comment(10)
Why don't you use std::array if you know the size from compile time?Logography
@40two the OP explicitly states that it does not know s before run time.Thoroughbred
@40two The size is not known at compile time.Prestonprestress
OP seems to want some VLA for member.Snowberry
this smells of premature optimization. which, according to Knuth, is Evil. use std::vector, measure the performance in release build.Mordacious
@G.Samaras You can use std::vector and call reserve(s) as soon as s is known. Or, you can construct those vectors at size s and not change their size after that.Prestonprestress
A downvote? Why? Is it is so obvious that it can be done as I am saying so? I searched so much and didn't find an answer before asking. The only thing I do not like with reserve is that may reserve more space than what you are asking. @Cheersandhth.-Alf, do not only see it by aspect of performace, see it from aspect of educating. :)Madalene
Moreover, assuming that the question is bad, I can not delete it, because it has two answers.Madalene
So, what can I do to delete the question?Madalene
I am asking why I got downvoted, so that I correct myself in the future (meta.#253326). Can the downvoter please help? :)Madalene
U
1

Two arrays having even the same element type but with different sizes are different types. So for example char[10] and char[11] are different types. The same way if two classes have a member with a type that differs between these two classes then the classes define different types and have different sizes (I mean operator sizeof). Also you may not instantiate an object of an incomplete type.

If your compiler supports class std::dynarray I would advice to use it. Otherwise you can use class std::vector

Ulrich answered 6/5, 2014 at 13:57 Comment(7)
Every class B will have the same exact size, but the compiler doesn't know that. std::dynarray is surely the way to go, but I have no support for C++14.Madalene
@G. Samaras In this case I do not see other way than to allocate manually a dynamic array.Ulrich
So, dynamic allocation (housekeeping is trivial) would be your choice, instead of a vector? Off-topic: Since the question is downvoted, I feel I should close it, but because there are answers, I can't. What should I do? However, your answer seems nice for future reference, when C++14 will be closer.Madalene
@G. Samaras It is not my choice. It is your choice because you said that you may not use standard containers. As for me then I have up voted your post.Ulrich
Isn't old arrays standard? I think I will go for std::vector, with reserve and shrink_to_fit. Thanks.Madalene
@G.Samaras if you are going to use shrink_to_fit, please, don't... either it does nothing or it gives you cache locality issues and it's O(N) to execute (since you have to copy each item to their new, smaller home). Usually it's cheaper to leave the slack in memory.Thoroughbred
I wasn't aware of the locality. Maybe you are right. I wrongly read (in the ref), linear to the difference of the actual size and the non-needed one. I will investigate. Thanks for the tip @Massa!Madalene
P
1

There are two issues. First, note nesting of classes is for scope only. A nested class doesn't automatically create a data member of that class in the outer class. So normally you would then define member(s), in the outer class, of the nested class type as shown below. Second, you can't define an array based on a size that is computed at run-time in C++.

That said, you could easily use a std::vector. If it all has to be done in the header file for some reason, you could define them in-class, though that would be a bad idea if they were more than a couple lines.

#include <vector>
#include <cstddef>

class A {
    private:
        class B {
            friend A;
            B(size_t n) : array(n) {}
            std::vector<int> array;
        };
    public:
        // Initialize b_member based on some computation.
        A(int i) : b_member(i + 2), b_ptr_member(new B(i + 3)) {}
        ~A() { delete b_ptr_member; }
    private:
        B b_member;
        B *b_ptr_member;
};

int main() {
    A a(10);
}
Phillipp answered 6/5, 2014 at 13:43 Comment(3)
The data members of A, will probably be pointers to class B. The constructor of B, will be called, n times, from the constructor of A. Doesn't that guarantee the order that in which the constructors are going to be called?Madalene
@G.Samaras: Yes, if you code it that way. I'll edit the answer to make that more clear.Phillipp
+1 for the analytical answer and for been the first to answer the question in a good way. However, I am choosing Vlad's answer, since it can be used by future users. :)Madalene
L
1

You can't declare an array of variable size in C++. The compiler must know the size of the array in advance. Use std::vector instead and then use std::vector::shrink_to_fit to reduce its capacity to fit its size.:

class B {
  ...
  std::vector<int> a;
  ...
};
Logography answered 6/5, 2014 at 13:43 Comment(5)
+1 for the shrink_to_fit idea. In the future, please read carefully the question of the OP, so that you do not do unnecessary comments and having to edit your answer so many times. If you think that I am wrong, let it go. :)Madalene
See Massa's comment in Vlad's answer about shrink_to_fit.Madalene
@G.Samaras take a look at #23502791Logography
Good thing that you asked! Fairly you got my +1!Madalene
@G.Samaras basically there's no better way to do it.Logography
U
1

Two arrays having even the same element type but with different sizes are different types. So for example char[10] and char[11] are different types. The same way if two classes have a member with a type that differs between these two classes then the classes define different types and have different sizes (I mean operator sizeof). Also you may not instantiate an object of an incomplete type.

If your compiler supports class std::dynarray I would advice to use it. Otherwise you can use class std::vector

Ulrich answered 6/5, 2014 at 13:57 Comment(7)
Every class B will have the same exact size, but the compiler doesn't know that. std::dynarray is surely the way to go, but I have no support for C++14.Madalene
@G. Samaras In this case I do not see other way than to allocate manually a dynamic array.Ulrich
So, dynamic allocation (housekeeping is trivial) would be your choice, instead of a vector? Off-topic: Since the question is downvoted, I feel I should close it, but because there are answers, I can't. What should I do? However, your answer seems nice for future reference, when C++14 will be closer.Madalene
@G. Samaras It is not my choice. It is your choice because you said that you may not use standard containers. As for me then I have up voted your post.Ulrich
Isn't old arrays standard? I think I will go for std::vector, with reserve and shrink_to_fit. Thanks.Madalene
@G.Samaras if you are going to use shrink_to_fit, please, don't... either it does nothing or it gives you cache locality issues and it's O(N) to execute (since you have to copy each item to their new, smaller home). Usually it's cheaper to leave the slack in memory.Thoroughbred
I wasn't aware of the locality. Maybe you are right. I wrongly read (in the ref), linear to the difference of the actual size and the non-needed one. I will investigate. Thanks for the tip @Massa!Madalene
T
1

The answer is: use std::vector. This item:

1)I need only the functionality of the old good arrays (discards vector)

does not really apply. You do need extra functionality that old good arrays do not have (namely, allocating an array for which you only have the size at run time).

If you have a recent compiler/standard library, maybe you have access to <experimental/dynarray>... which, IMHO, is just a crippled version of <vector>, but to each, its own :D

Thoroughbred answered 6/5, 2014 at 14:31 Comment(1)
I had in mind the functionality I would need, as soon as, the structure was created. +1 for noting about the needs!Madalene

© 2022 - 2024 — McMap. All rights reserved.