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.

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • Why don't you use `std::array` if you know the size from compile time? – 101010 May 06 '14 at 13:38
  • @40two the OP explicitly states that it does not know `s` before run time. – Massa May 06 '14 at 13:42
  • @40two The size is *not* known at compile time. – iavr May 06 '14 at 13:42
  • OP seems to want some VLA for member. – Jarod42 May 06 '14 at 13:43
  • 1
    this smells of *premature optimization*. which, according to Knuth, is Evil. use `std::vector`, measure the performance in release build. – Cheers and hth. - Alf May 06 '14 at 13:44
  • @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. – iavr May 06 '14 at 13:45
  • 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. :) – gsamaras May 06 '14 at 13:57
  • Moreover, assuming that the question is bad, I can not delete it, because it has two answers. – gsamaras May 06 '14 at 13:59
  • So, what can I do to delete the question? – gsamaras May 06 '14 at 14:12
  • I am asking why I got downvoted, so that I correct myself in the future (http://meta.stackoverflow.com/questions/252826/is-asking-reasons-for-downvote-in-comments-non-constructive). Can the downvoter please help? :) – gsamaras May 06 '14 at 14:28

4 Answers4

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);
}
kec
  • 2,099
  • 11
  • 17
  • 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? – gsamaras May 06 '14 at 14:01
  • @G.Samaras: Yes, if you code it that way. I'll edit the answer to make that more clear. – kec May 06 '14 at 14:22
  • +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. :) – gsamaras May 06 '14 at 16:02
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;
  ...
};
101010
  • 41,839
  • 11
  • 94
  • 168
  • +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. :) – gsamaras May 06 '14 at 16:00
  • See Massa's comment in Vlad's answer about `shrink_to_fit`. – gsamaras May 06 '14 at 17:03
  • @G.Samaras take a look at http://stackoverflow.com/questions/23502291/is-shrink-to-fit-the-proper-way-of-reducing-the-capacity-a-stdvector-to-it – 101010 May 06 '14 at 20:22
  • Good thing that you asked! Fairly you got my +1! – gsamaras May 06 '14 at 21:08
  • @G.Samaras basically there's no better way to do it. – 101010 May 06 '14 at 21:15
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

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 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. – gsamaras May 06 '14 at 14:05
  • @G. Samaras In this case I do not see other way than to allocate manually a dynamic array. – Vlad from Moscow May 06 '14 at 14:17
  • 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. – gsamaras May 06 '14 at 14:22
  • @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. – Vlad from Moscow May 06 '14 at 14:30
  • Isn't old arrays standard? I think I will go for `std::vector`, with `reserve` and `shrink_to_fit`. Thanks. – gsamaras May 06 '14 at 14:35
  • @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. – Massa May 06 '14 at 16:56
  • 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! – gsamaras May 06 '14 at 17:03
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

Massa
  • 8,647
  • 2
  • 25
  • 26
  • I had in mind the functionality I would need, as soon as, the structure was created. +1 for noting about the needs! – gsamaras May 06 '14 at 16:01