当一个是 const 时如何交换智能指针

How to swap smart pointers when one is const

我有以下问题

Buffer buffer1;
Buffer buffer2;

std::unique_ptr<const Buffer> hotBuffer;
std::unique_ptr<Buffer> backBuffer;

我想在读取热缓冲区时填充后台缓冲区,并希望热缓冲区不可写,因此 const,但在读取后的某个时刻后台缓冲区已满 我想交换这些缓冲区。这些缓冲区非常大,所以我不希望它们被复制,因此 unique_ptr 交换。

我想按照以下方式做一些事情:

hotBuffer.swap(backBuffer);

但无论我尝试何种 const_cast 变体,它似乎都无法正常工作...

是否有解决方案或这种精神错乱?

要交换,您需要兼容的 const 资格,否则指向 const 的指针将需要转换为指向非常量的指针。要获得兼容的 const 资格,您必须创建一个临时的并按照 Igor 的评论建议进行转换。

所以...像这样:

template<typename U, typename T>
std::unique_ptr<U> const_pointer_cast(std::unique_ptr<T>&& ptr) {
    return std::unique_ptr<U>(const_cast<U*>(ptr.release()));
}

void swap_buffers(std::unique_ptr<const Buffer>& hotBuffer, std::unique_ptr<Buffer>& backBuffer) {
    backBuffer = const_pointer_cast<Buffer>(std::exchange(hotBuffer, std::move(backBuffer)));
}

I want to fill the back buffer while the hot buffer is being read, and want the hot buffer to be un-writable and const for this reason,

因此您决定更改您的实现以强制执行您想要的接口。通常,这是一种次优的方法。

最好封装更多。我会将这些变量重新设想为 class,其中 在内部 两个缓冲区都是可写的,但外部代码将热缓冲区视为 const。 (如果这些变量已经在 class 中,请将它们重新想象为嵌套的 class。)这将是一个小型 class,具有单一的、集中的目的——控制内存的哪个区域被认为是“热”,而被认为是“后退”。例如:

// Not sold on the name, but it will do for this demonstration
class BufferManager {
public:
    // Instead of access to the smart pointers, provide direct access to the buffers.
    // (Hide the detail of where these buffers live.)
    const Buffer & hotBuffer() const { return *hot; }
    Buffer &       backBuffer()      { return *back; }
    
    // A way for external code to say it is time to swap buffers:
    void flip() { hot.swap(back); }

    // Placeholder constructor; modify to suit your needs:
    BufferManager() : hot(std::make_unique<Buffer>()),
                      back(std::make_unique<Buffer>())
    {}

private:
    std::unique_ptr<Buffer> hot;
    std::unique_ptr<Buffer> back;
};

使用这种方法,两个智能指针都指向可修改的内容,因此交换它们不再有问题。但是,此 class 之外的任何内容都将热缓冲区视为 const.

您可能想尝试一下这些名称。 (由于您需要 BufferManager 变量的名称,因此将访问函数命名为 hotback 可能就足够了,这当然意味着重命名私有数据成员。)界面可能需要改进。要点是您添加了一个抽象层,以便 接口 在适当的时候应用 const,而不是实现。

注:可能将填充后台缓冲区的代码合并到此class中是合适的。也许后台缓冲区和 flip() 都可以设为私有。要记住的关键是 class 中的任何内容都不应该对读取热缓冲区感兴趣。那是给外部代码来处理的。如果这样做了,这个 class 的目的就变成了提供热缓冲区。