c++ - 指向std::unique_ptr <type,custom_deleter>的byte []的指针不编译

标签 c++

我有一个应该使用自定义删除器删除的类型。
对于分配,我使用带有byte []的new放置。
我也想在分配时返回一个unique_ptr。
不幸的是,分配不起作用。
我尝试了这个:

std::unique_ptr<CustomType*, CustomTypeDeleter>
allocate_node(const std::string& value, int levels)
{
    // get size of Skip_node
    const auto node_size =
        sizeof(CustomType) + (levels - 1) * sizeof(CustomType*);

    // allocate memory
    std::unique_ptr<std::byte[]> node = std::make_unique<std::byte[]>(node_size);

    // construct object in allocated space
    new (node.get()) CustomType{value, levels, {nullptr}};

    // transform byte[] into std::unique_ptr<Skip_node*, Skip_node_deleter>
    return {reinterpret_cast<CustomType*>(node.release())};  //does not work
}
不幸的是,最后一行不起作用。我本来希望我们将byte []转换为std::unique_ptr ,但会收到此编译错误:
g++ -c -pipe -g -std=gnu++1z -Wall -Wextra -fPIC -DQT_QML_DEBUG -I../untitled -I. -I../Qt/5.15.0/gcc_64/mkspecs/linux-g++ -o main.o ../untitled/main.cpp
../untitled/main.cpp: In function ‘std::unique_ptr<CustomType*, CustomTypeDeleter> allocate_node(const string&, int)’:
../untitled/main.cpp:38:58: error: could not convert ‘{((CustomType*)node.std::unique_ptr<std::byte []>::release())}’ from ‘<brace-enclosed initializer list>’ to ‘std::unique_ptr<CustomType*, CustomTypeDeleter>’
   38 |     return {reinterpret_cast<CustomType*>(node.release())};  //does not work
      |                                                          ^
      |                                                          |
      |                                                          <brace-enclosed initializer list>
In file included from /usr/include/c++/10.2.0/memory:83,
                 from ../untitled/main.cpp:2:
/usr/include/c++/10.2.0/bits/unique_ptr.h: In instantiation of ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = CustomType*; _Dp = CustomTypeDeleter]’:
../untitled/main.cpp:43:40:   required from here
/usr/include/c++/10.2.0/bits/unique_ptr.h:357:56: error: static assertion failed: unique_ptr's deleter must be invocable with a pointer
  357 |  static_assert(__is_invocable<deleter_type&, pointer>::value,
      |                                                        ^~~~~
/usr/include/c++/10.2.0/bits/unique_ptr.h:361:17: error: no match for call to ‘(std::unique_ptr<CustomType*, CustomTypeDeleter>::deleter_type {aka CustomTypeDeleter}) (std::remove_reference<CustomType**&>::type)’
  361 |    get_deleter()(std::move(__ptr));
      |    ~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
../untitled/main.cpp:13:10: note: candidate: ‘void CustomTypeDeleter::operator()(CustomType*) const’
   13 |     void operator()(CustomType* p) const noexcept
      |          ^~~~~~~~
../untitled/main.cpp:13:33: note:   no known conversion for argument 1 from ‘std::remove_reference<CustomType**&>::type’ {aka ‘CustomType**’} to ‘CustomType*’
   13 |     void operator()(CustomType* p) const noexcept
      |                     ~~~~~~~~~~~~^
make: *** [Makefile:725: main.o] Error 1
11:55:23: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project untitled (kit: Desktop Qt 5.15.0 GCC 64bit)
When executing step "Make"
最小示例:
#include <string>
#include <memory>
#include <cstddef>

struct CustomType {
    std::string value;
    int levels;
    CustomType* next[1];
};

class CustomTypeDeleter {
public:
    void operator()(CustomType* p) const noexcept
    {
        if (p) {
            p->~CustomType();

            auto raw_p = reinterpret_cast<std::byte*>(p);
            delete[] raw_p;
        }
    }
};

std::unique_ptr<CustomType*, CustomTypeDeleter>
allocate_node(const std::string& value, int levels)
{
    // get size of Skip_node
    const auto node_size =
        sizeof(CustomType) + (levels - 1) * sizeof(CustomType*);

    // allocate memory
    std::unique_ptr<std::byte[]> node = std::make_unique<std::byte[]>(node_size);

    // construct object in allocated space
    new (node.get()) CustomType{value, levels, {nullptr}};

    // transform byte[] into std::unique_ptr<Skip_node*, Skip_node_deleter>
    return {reinterpret_cast<CustomType*>(node.release())};  //does not work
}

int main()
{
    auto node = allocate_node("test", 3);
}

最佳答案

您需要返回一个std::unique_ptr<CustomType, CustomTypeDeleter>(而不是std::unique_ptr<CustomType*, CustomTypeDeleter>),并且需要一个deleter实例:

std::unique_ptr<CustomType, CustomTypeDeleter>
allocate_node(const std::string& value, int levels)
{
    //...
    return {reinterpret_cast<CustomType*>(node.release()), CustomTypeDeleter{}};
}
功能齐全:
std::unique_ptr<CustomType, CustomTypeDeleter>
allocate_node(const std::string& value, unsigned levels) {
    // get size of Skip_node
    const auto node_size = sizeof(CustomType) + (levels - 1U) * sizeof(CustomType*);

    // allocate memory
    auto raw = new std::byte[node_size];

    // construct object in allocated space
    auto rv = new(raw) CustomType{value, levels}; // use return value from new
    std::fill_n(rv->next, levels - 1U, nullptr); // set all to nullptr, not only one

    return {rv, CustomTypeDeleter{}};
}
Demo
请注意,超出范围访问next具有未定义的行为(尽管可能会起作用)。
同样,数组对象从技术上来说还没有开始生存,直到您对其进行new编码。
这是一种不会使程序具有未定义行为的替代方法:
struct CustomType {
    std::string value;
    unsigned levels;
    CustomType** const next; // not a CustomType*[]
};

template<typename T, typename ArrT>
class CustomTypeDeleter {
public:
    void operator()(T* p) const noexcept {
        if(p) {
            p->~T(); // main object destructor

            // call destructor on an array of objects
            for(size_t i=0; i < p->levels; ++i) p->next[i].~ArrT();

            // delete memory
            delete[] reinterpret_cast<std::byte*>(p);            
        }
    }
};

static std::unique_ptr<CustomType, CustomTypeDeleter<CustomType, CustomType*>> 
allocate_node(const std::string& value, unsigned levels) {

    // get size of Skip_node
    auto node_arr_align = std::max(sizeof(CustomType), sizeof(CustomType*));
    auto node_size = node_arr_align + levels * sizeof(CustomType*);

    // allocate memory
    auto raw = new std::byte[node_size];

    // start lifetime of array objects
    auto arr = new(raw + node_arr_align) CustomType*[levels]{};

    // construct object in allocated space
    auto rv = new(raw) CustomType{value, levels, arr}; // use return value from new

    return {rv, CustomTypeDeleter<CustomType, CustomType*>{}}; 
}

关于c++ - 指向std::unique_ptr <type,custom_deleter>的byte []的指针不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64292155/

相关文章:

c++ - 多态异常处理和编译器警告

c++ - 表达式 "variable, variable = value;"

c++ - 你会推荐这种复制字符串的方法吗?

c++ - 如何使用 ov_open_callbacks 从流中打开 Ogg Vorbis 文件

c++ - 最低共同祖先( boost 图)

c++ - 当其他构造函数存在时,为什么 "ctor() = default"会改变行为?

c++ - 在 C/C++ 中乘以小数(相对于高数)是否更快?

c++ - 输出是垃圾值

c++ - 我应该向 glTexSubImage2D 提供完整图像还是部分图像?

c++ - C++读取整个文件目录