0

I was experimenting with template specialisations by recreating a basic std::unique_ptr when I realised that the following code compiles and runs successfully:

namespace not_std {

template<typename T>
class unique_ptr
{
public:
    unique_ptr(T *pointer)
        : pointer_(pointer)
    { }

    ~unique_ptr()
    {
        delete pointer_;
    }

private:
    T *pointer_;
};

template<typename T>
class unique_ptr<T[]>
{
public:
    unique_ptr(T *pointer)
        : pointer_(pointer)
    { }

    ~unique_ptr()
    {
        delete[] pointer_;
    }

private:
    T *pointer_;
};

} // namespace not_std

int main()
{
    not_std::unique_ptr<char[]> buffer(char[64]);
}

Note that I'm not looking for feedback on the implementation so I've stripped out irrelevant sections of the class definition.

At first I thought it was a bug in my implementation, but it turns out that even with the standard implementation, this code compiles and runs.

I thought this code would break because char[64] looks to me like an anonymous stack-allocated array. If this is the case, then it has a lifetime that ends when the constructor for std::unique_ptr returns. Then wouldn't the destructor be calling delete[] on stack-allocated memory that is also now out of scope?

Maybe I'm misunderstanding what exactly is happening, since I've never seen this syntax before, where an array T[N] is directly passed as a parameter.

I appreciate any clarifications/explanations.

ThatBantIsClass
  • 42
  • 1
  • 1
  • 5

1 Answers1

0

Right as I was about to post this question, I figured out the the issue:

  1. unique_ptr<char[]> buffer(char[64]) actually declares a function called buffer that takes a char[64] as an unnamed parameter and returns a unique_ptr<char[]>. So this is actually an instance of the most vexing parse as pointed out by @xaxxon.

  2. Arrays cannot be initialised with this syntax: char[64]

  3. Passing a temporary array is not standard compliant but is possible with clang. It would instead look like unique_ptr<char[]> buffer((char[64]){ }), and does indeed cause a segfault, as expected.

Note that this is not a suggestion that passing stack-allocated arrays is ever a good idea.

Thought it would be worthwhile to let others know so they don't repeat the same mistake I made...

ThatBantIsClass
  • 42
  • 1
  • 1
  • 5
  • 1
    https://en.wikipedia.org/wiki/Most_vexing_parse – xaxxon Dec 19 '20 at 21:51
  • That is still broken, as your character array is destroyed as soon as that line completes, but then your unique_ptr will try to delete it when its scope ends and that's double-delete UB. You should be using `new` to allocate the character array or `make_unique` – xaxxon Dec 19 '20 at 21:54
  • 1
    @xaxxon They are aware of the problem, they are trying to produce observable problems as a result of this UB. – François Andrieux Dec 19 '20 at 22:01
  • I understand that the code I showed above is not good practice. I don't believe I ever suggested it was. I would also like to understand why whoever downvoted this answer thought it was not useful, given that I thought this instance of the most vexing parse was slightly more obfuscated by array syntax. – ThatBantIsClass Dec 19 '20 at 22:03
  • @FrançoisAndrieux My comment says UB. Maybe I edited it? I don't remember. Maybe you @'d the wrong person? – xaxxon Dec 19 '20 at 22:45
  • 1
    @ThatBantIsClass I downvoted the answer because it has significant parts that are wrong. For example there are multiple problems with part 3. But also in general because the question and answer are duplicates of other better answers. – xaxxon Dec 19 '20 at 22:47
  • @xaxxon Yes, you're right sorry. My first comment was @ you, but my second was @ OP. – François Andrieux Dec 19 '20 at 22:50
  • 2
    @ThatBantIsClass You are deleteing an object that was not newed. Your deduction was correct that this would be an error. However you are incorrect in expecting it to segfault. The error leads to Undefined Behavior and it might segfault, it might produce no observable problem, it might corrupt unrelated objects or it might do anything else imagining. You should not expect errors to always result in an obvious or even detectable event. – François Andrieux Dec 19 '20 at 22:50