1

I want to initialize a array of 1 million objects on stack, I need to write one million &i in the following code. Is there any other good way.

#include <iostream>

class A{
public:
    A(int* p)
       : p_(p){
        std::cout << "A" << std::endl;  
    }   

private:
    int *p_;
};

int main(){
   int i;
   A a[3] = {&i, &i, &i};
}
colin
  • 51
  • 2
  • @po.pe yes, it would – Remy Lebeau Jul 24 '20 at 06:45
  • @po.pe - the op want to allocate 1 million objects on the `stack`. so your comment is wrong! `vector` is a heap alocated DS – Adam Jul 24 '20 at 06:58
  • Putting 1m `A` objects on the stack is likely to overflow the stack, since the default stack size per thread is typically 1MB but 1m `A`s would require ~4MB (32bit) or ~8MB (64bit). – Remy Lebeau Jul 24 '20 at 07:06
  • 3
    @OP -- Why specifically do you want to allocate on the stack? You're starting to go [XY](http://xyproblem.info/) here. – PaulMcKenzie Jul 24 '20 at 07:06
  • yes, on stack, not necessarily a million. I just want to show that if there are many objects, it will be very troublesome to use this method. Why can't it be written like this in c++, A a[100] = {&i} – colin Jul 24 '20 at 07:44
  • But we know that it is troublesome if the stack memory is exhausted without having to show any code. It's like saying that going into a lion's den is dangerous, and then to prove it, you go into the lion's den. – PaulMcKenzie Jul 24 '20 at 08:09

3 Answers3

3
#include <iostream>
#include <type_traits>

class A{
public:
    A(int* p)
        : p_(p){
            std::cout << "A" << std::endl;
    }
private:
    int *p_;
};

int main(){
    using elemType = std::aligned_storage<sizeof(A), alignof(A)>::type;
    const size_t count = 1000000;

    int i;
    elemType a[count];

    for(int idx = 0; idx < count: ++idx) {
         new (&a[idx]) A(&i);
    }

    ...

    for(int idx = 0; idx < count: ++idx) {
         reinterpret_cast<A&>(a[idx]).~A();
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • @AliAskari I wrote my own answer and posted it before I saw yours. My answer uses properly aligned array elements, yours does not. And I call element destructors (though it is trivial in this example), yours does not. – Remy Lebeau Jul 24 '20 at 06:45
  • 1
    There is no need to call destructor because class A does not implemented destructor and also buffer's memory is on stack. – Ali Askari Jul 24 '20 at 06:52
  • Wouldn't it be better to separate groups of zeros with `'` in C++? – machine_1 Jul 24 '20 at 06:56
  • @RemyLebeau - why calling elements destructors if your array/container is alocated on the `stack`?? – Adam Jul 24 '20 at 07:04
  • 1
    @AliAskari in this particular example, `A`'s destructor is a no-op, but in real production code, that may not be the case. Whenever an object is explicitly `new`'ed, it should also be explicitly destructed. – Remy Lebeau Jul 24 '20 at 07:08
  • @machine_1 that syntax is only supported in C++14 and later – Remy Lebeau Jul 24 '20 at 07:12
  • 2
    @Adam object construction/destruction is separate from memory allocation/deallocation. Imagine if `A` had non-trivial data members, like `std::string`. The array of `A`s may be on the stack, but the individual `A`s would still need to have their constructor and destructor called to manage the data members correctly. – Remy Lebeau Jul 24 '20 at 07:16
  • @RemyLebeau - you are right. we can allocate the container on the `stack` but the objects inside the container can be allocated on the `heap` . in this question we are storing integers or int pointers so the destructor is not needed. – Adam Jul 24 '20 at 07:24
  • 2
    @Adam IN THIS EXAMPLE, yes. But IN GENERAL, when introducing the concept of using `placement-new`, one should also introduce the concept of calling destructors, too. Even for trivial types (yes, destructors can be called on them too, even if they are just no-ops). – Remy Lebeau Jul 24 '20 at 07:41
  • You have a shadowing problem here: `new (&a[i]) A(&i)` (the loop counter `i` shadows the `i` outside the loop). – chtz Jul 24 '20 at 08:54
  • @chtz good catch. I fixed it – Remy Lebeau Jul 24 '20 at 08:56
1

C++ new operator can be used to call constructor on a preallocated memory:

#include <iostream>
#include <cstddef>
#include <cstdint>


class A{
public:
    A(int* p)
       : p_(p){
        std::cout << "A" << std::endl;  
    }   

private:
    int *p_;
};

int main(){
   int i;
   uint8_t buf[1000000 * sizeof(A)];

   A* pa = reinterpret_cast<A*>(buf);

   for (size_t n = 0; n < 1000000; n++) {
       new (&pa[n]) A(&i);
   }

   return 0;
}
Ali Askari
  • 515
  • 3
  • 8
0

You could use std::vector and initialize is with a million elements

std::vector<A> a(1000000, &i);
po.pe
  • 1,047
  • 1
  • 12
  • 27
  • 1
    the op want to allocate 1 million objects on the `stack`. so your answer is 100% wrong! `vector` is a heap alocated DS – Adam Jul 24 '20 at 06:59