8

I am trying to write a factory function that creates a constexpr object that uses new. Is this even possible? The following code does not compile:

aa.cpp: In function ‘int main()’: aa.cpp:23:39: in ‘constexpr’ expansion of ‘((Buffer*)(& b))->Buffer::~Buffer()’ aa.cpp:10:36: error: deallocation of already deallocated storage 10 |
constexpr ~Buffer() { delete[] data; }

#include <random>
struct Buffer {
    int size;
    int* data;

    constexpr Buffer(int n) : size(n), data(new int[n])
    {
        for (int i = 0; i < n; ++i) data[i] = i;
    }

    constexpr ~Buffer() { delete[] data; }

    constexpr int get(int i) const { return data[i]; }
    static constexpr Buffer Create(int n)
    {
        Buffer buf(n);
        // ...
        return buf; 

    }
};

constexpr void test(int d)
{
    Buffer b2(d);
}

int main() {
    constexpr Buffer b = Buffer::Create(4);
    constexpr Buffer b2(43); // also does not compile: error: ‘Buffer(43)’ is not a constant expression because it refers to a result of ‘operator new’
    test(rand()); // This is Ok
}

3
  • 1
    You know you can just use std::vector, right? It has the same limitations as your class. Commented Aug 17 at 8:52
  • This useless struct is, of course, just an example Commented Aug 17 at 9:26
  • Since the constructor alone does not compile, why introduce the complexity of a factory function? Commented Aug 17 at 17:56

2 Answers 2

9

While constexpr does allow certain uses of operator new, it does not allow storing the result of operator new for use at runtime (more specifically, the new memory must be deleted in the same compile-time expression).

Think about it: how would a compile-time heap allocation be usable at runtime?

You can use heap allocations at compile-time only, or at runtime only. Not a mix of both for the same allocation.

Here is a valid example:

struct Buffer {
    constexpr Buffer(int n)
    {
        int* data = new int[n];
        for (int i = 0; i < n; ++i)
            data[i] = i;
        delete[] data;
    }
};
Sign up to request clarification or add additional context in comments.

3 Comments

I don't see what this has to do with the error message shown in the question; what you've said here is obviously true but deallocation of already deallocated storage sounds more like a rule-of-5 violation to me...
There are two error messages in the question. My answer is more directly about the second one ("is not a constant expression") but it's all kind of the same root cause.
@ildjarn The standard requires that the concern be diagnosed. It doesn't impose any requirements for wording (or even clarity) of the diagnostic (error, warning, etc) message. At a guess, a message like "deallocation of already deallocated storage" in a constexpr destructor probably reflects reasoning in the compiler design that a constexpr function should not be deallocating anything it doesn't actually allocate.
3

You can't create a constexpr object that requires dynamically allocated memory. You can allocate memory in a constexpr context, but you must release it before the constexpr context ends.

As for test(rand()); // This is Ok, it's not actually executed at compile time. constexpr function is not guaranteed to be executed at compile time unless it's used to initialize a constexpr variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.