How do I declare an array of objects whose class has no default constructor?

后端 未结 13 1031
时光取名叫无心
时光取名叫无心 2020-11-30 06:25

If a class has only one constructor with one parameter, how to declare an array? I know that vector is recommended in this case. For example, if I have a class



        
相关标签:
13条回答
  • 2020-11-30 06:35

    When you declare an object that has no default constructor, you must initialize it in the declaration.

    Foo a; // not allowed
    Foo b(0); // OK
    

    The same goes for arrays of such types:

    Foo c[2]; // not allowed
    Foo d[2] = { 0, 1 }; // OK
    Foo e[] = { Foo(0), Foo(1), Foo(2) }; // also OK
    

    In your case, you'll probably find it impractical to initialize all 10,000 elements like that, so you might wish to rethink whether the class really shouldn't have a default constructor.

    0 讨论(0)
  • 2020-11-30 06:35

    In straight C, using int foo[10000] = {1}; will initialize the first array item to 1 and the remainder of the array to zero. Does C++ not auto-initialize unspecified array members, or does this require a default constructor?

    0 讨论(0)
  • 2020-11-30 06:39

    You have to use the aggregate initializer, with 10000 of inidividual initializers between the {}

    Foo array[10000] = { 1, 2, 3, ..., 10000 };
    

    Of course, specifying 10000 initializers is something from the realm of impossible, but you asked for it yourself. You wanted to declare an array of 10000 objects with no default constructor.

    0 讨论(0)
  • 2020-11-30 06:41

    sbi had the best answer for plain arrays, but didn't give an example. So...

    You should use placement new:

    char *place = new char [sizeof(Foo) * 10000];
    Foo *fooArray = reinterpret_cast<Foo *>(place);
    for (unsigned int i = 0; i < 10000; ++i) {
        new (fooArray + i) Foo(i); // Call non-default constructor
    }
    

    Keep in mind that when using placement new, you are responsible for calling the objects' destructors -- the compiler won't do it for you:

    // In some cleanup code somewhere ...
    for (unsigned int i = 0; i < 10000; ++i) {
        fooArray[i].~Foo();
    }
    
    // Don't forget to delete the "place"
    delete [] reinterpret_cast<char *>(fooArray);
    

    This is about the only time you ever see a legitimate explicit call to a destructor.

    NOTE: The first version of this had a subtle bug when deleting the "place". It's important to cast the "place" back to the same type that was newed. In other words, fooArray must be cast back to char * when deleting it. See the comments below for an explanation.

    0 讨论(0)
  • 2020-11-30 06:47

    Try this.

    Foo **ppInstances=0;
        size_t total_instances = 10000;
    
        for(int parent=0;parent < total_instances;parent++){
            ppInstances[parent]=new Foo( parent ); 
            ppInstances++;
        }
        for(int parent=0;parent < total_instances;parent++){
            delete *ppInstances;
            ppInstances--;
        }
    

    0 讨论(0)
  • 2020-11-30 06:49

    The proper way is use to std::aligned_storage. You will have to manually construct and destruct items as well as reintrepret_cast when you want to access an item. I recommend you write a small wrapper class around storage_t to take care of this. Someone mentioned using boost::optional which uses a bool and a storage_t under the hood. This method saves you a bool.

    template<typename T>
    using storage_t = typename std::aligned_storage<sizeof(T), alignof(T)>::type;
    
    struct Foo;
    
    size_t i = 55;
    storage_t<Foo> items[1000]; // array of suitable storage for 1000 T's
    new (reintrepret_cast<Foo*>(items + i)) Foo(42); // construct new Foo using placement new
    *reintrepret_cast<Foo*>(items + i) = Foo(27);    // assign Foo
    reintrepret_cast<Foo*>(items + i)->~Foo()        // call destructor
    
    0 讨论(0)
提交回复
热议问题