0

I'm trying to inherit unique_ptr<T[]> just to add a constructor which allocates the array using malloc and sets a const size field.

#include <memory>
#include <functional>

using std::function;
using std::unique_ptr;
using std::byte;


template<class _Tp, class _Dp = function<void(_Tp*)>>
class unique_array_ptr : public unique_ptr<_Tp[], _Dp> {
public:
    using unique_ptr<_Tp[], _Dp>::unique_ptr;
    unique_array_ptr(const size_t size) : unique_ptr<_Tp[], _Dp>((_Tp*) malloc(size), free), size(size) {}
    const size_t size;
};

void move() {
    unique_ptr<byte> hello(new byte[5]);
    unique_array_ptr<byte> test = std::move(hello);
}

The test assignment triggers this error:

<source>: In function 'void move()':
<source>:18:44: error: conversion from 'std::remove_reference<std::unique_ptr<std::byte>&>::type' {aka 'std::unique_ptr<std::byte>'} to non-scalar type 'unique_array_ptr<std::byte>' requested
   18 |     unique_array_ptr<byte> test = std::move(hello);
      |                                   ~~~~~~~~~^~~~~~~

Also before anyone says just use std::vector, I'm working with a C library so I need to be able to pass in buffers that it can free later.

I tried to inherit the constructors with using unique_ptr<_Tp[], _Dp>::unique_ptr; but something isn't working.

Update:

I changed it to this but I still get no viable conversion.

unique_ptr<byte[], function<void(byte*)>> hello(new byte[5]);
unique_array_ptr<byte> test = std::move(hello);
  • 6
    Why do you need to inherit from `std::unique_ptr`? What is the original and underlying problem that's supposed to solve? Can't it be solved through e.g. composition? Also remember that `std::unique_ptr` doesn't have a `virtual` [destructor](https://en.cppreference.com/w/cpp/memory/unique_ptr/~unique_ptr) which could lead to problems. – Some programmer dude Mar 08 '23 at 08:49
  • 1
    Why do you want it to work? The source object allocated memory with `new`, taking ownership of it to later free with `free` would actually be undesirable, no? – HolyBlackCat Mar 08 '23 at 08:51
  • `malloc` is wrong for most `_Tp`. Who will construct the elements? – 463035818_is_not_an_ai Mar 08 '23 at 08:52
  • Also you probably shouldn't use `std::function` to avoid overhead. Write your own deleter class. – HolyBlackCat Mar 08 '23 at 08:54
  • 1
    "I need to be able to pass in buffers that it can free later." maybe I dont get it but thats something you can do with a vector – 463035818_is_not_an_ai Mar 08 '23 at 08:56
  • 1
    suppose you would inherit the constructors and call them then all but your constructor will leave `size` uninitialized, they cannot work – 463035818_is_not_an_ai Mar 08 '23 at 09:03
  • I just want a smart pointer wrapping an array like there already is, but with a size field. – Dylan Bradshaw Mar 08 '23 at 09:04
  • looks like a [xy question](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). If you need a smart pointer with a size field you should ask a new question about that. – 463035818_is_not_an_ai Mar 08 '23 at 09:12
  • @463035818_is_not_a_number If I passed a vectors underlying buffer into the C library first of all I would need to ensure the vector is kept alive which I don't want to do, and secondly the library eventually calls free which would be undefined behavior. – Dylan Bradshaw Mar 08 '23 at 09:14
  • oh sorry misread, I thought its you who calls `free` later. Though it sounds weird that the library requires you to call `malloc` and it later calls `free` – 463035818_is_not_an_ai Mar 08 '23 at 09:21
  • 1
    `I just want a smart pointer wrapping an array like there already is, but with a size field.` Impossible without introducing Undefined Behavior. [Here some "crazy person" complains about it](https://youtu.be/IAdLwUXRUvg?t=920). If you place size information with a pointer then you just get more or less a `std::vector`. – Marek R Mar 08 '23 at 09:54
  • What you need is perhaps [make_unique_for_overwrite](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique) that allocates an uninitialized buffer. – BoP Mar 08 '23 at 10:08
  • 1
    You say that you are "working with a C library so I need to be able to pass in buffers that **it** can free later" (emphasis mine)? Is it the *library* that will free the data? Then smart pointers perhaps isn't such a good idea. Perhaps you should write your own thin wrapper-class around the API of the library you use? – Some programmer dude Mar 08 '23 at 11:37
  • @Someprogrammerdude So I have a class which stores the data (was using a std::vector). I sometimes want to be able to pass this buffer, without needlessly copying it, into a C library which will then handle the memory by freeing it later (not possible with std::vector). Using a unique_ptr I can simply call release() and pass the buffer to the C library with no issue other than having to separately keep track of the size of the buffer which I don't want. – Dylan Bradshaw Mar 08 '23 at 19:45

1 Answers1

2

unique_ptr<byte> hello(new byte[5]);

This isn't a unique_ptr<byte[], function<void(_Tp*)>>, but a unique_ptr<byte, default_delete<byte>>, so no reason why it would be interoperable with your class.

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157