Are there any issues with allocating memory within constructor initialization lists?

前端 未结 7 901
后悔当初
后悔当初 2020-12-05 10:50

I have used initialization lists a great deal in my C++ programs but wasn\'t aware that you could allocate memory within them.

So you can do something (as a contrive

相关标签:
7条回答
  • 2020-12-05 11:03

    Steve Jessop's answer presents pitfalls.

    About the order, which I think is what your question addressed:

    12.6.2/4

    Initialization shall proceed in the following order:

    [...]

    • Then, nonstatic data members shall be initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

    Since in your class, count is declared before k, you're ok.

    0 讨论(0)
  • 2020-12-05 11:06

    There's no problem with your initialization -- they are guaranteed by the standard to be done in order, however, do remember that if any of those allocations fails, the former ones won't be freed.

    So the only downside is if you want to keep safe against a failed allocation -- then you'd rather want to initialize them to nil and in the constructor wrap the allocation up in a try block. That is usually not needed though, unless your application is in the real danger of running out of memory, and needs to recover from that.

    Of course that holds true assuming that only a lack of memory can throw an exception -- if you allocate objects that can throw other exceptions, you should be more worried about it.

    0 讨论(0)
  • 2020-12-05 11:08

    There's no specific issue with calling new from the initializer list.

    However, if you do it for multiple members, it won't be exception-safe, and you risk leaking memory (what if the first new call succeeds, but the second throws an exception? Then the first allocation is leaked).

    As for relying on the initialization order, that's perfectly safe. Members are initialized in the order in which they're listed in the class declaration. So you can use the value of members initialized early, to initialize "later" members.

    Just keep in mind that it's their declaration order inside the class, and not their order in the initialization list that determines their initialization order. :)

    0 讨论(0)
  • 2020-12-05 11:13

    You are allocating memory in your initialiser-list; this is totally fine, but you are then assigning the pointers to that memory to raw pointers.

    These raw pointers do not imply any sort of memory ownership or deletion of the pointers that they point to, and as a result, the code contains several memory leaks, does not follow the "Rule of Five", and is generally bad.

    A far better way to write Test would be:

    class Test
    {
    private:
        //Assuming you actually want dynamic memory allocation:
        std::unique_ptr<int> i;
        std::unique_ptr<int[]> j;
        int count;
        std::unique_ptr<int[]> k;
    
    public:
        Test(void) : i(new int), j(new int[10]), count(10), k(new int[count])
        {
        }
    };
    
    0 讨论(0)
  • 2020-12-05 11:15

    Suppose that you have:

    class Foo
    {
    public:
        T* p1;
        T* p2;
    
        Foo()
        : p1(new T),
          p2(new T)
        {
        }
    };
    

    If initializing p2 fails (either because new throws an out of memory exception or because the T constructor fails), then p1 will be leaked. To combat this, C++ allows using try/catch in initialization lists, but it's usually pretty gross.

    0 讨论(0)
  • 2020-12-05 11:23

    It's not exception-safe. If the new for j throws an exception then the destructor for Test is not called, and so the memory for i is not freed.

    The destructor of i is called if the initializer for j throws, it's just that a raw pointer has no destructor. So you could make it exception-safe by replacing i with a suitable smart pointer. In this case, unique_ptr<int> for i and unique_ptr<int[]> for j would do.

    You can rely on the initializers to be executed in their correct order (the order the members are defined, not necessarily the order in the list). They can safely use data members that have already been initialized, so there's no problem with using count in the initializer for k.

    0 讨论(0)
提交回复
热议问题