当一个是 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
变量的名称,因此将访问函数命名为 hot
和 back
可能就足够了,这当然意味着重命名私有数据成员。)界面可能需要改进。要点是您添加了一个抽象层,以便 接口 在适当的时候应用 const
,而不是实现。
注:可能将填充后台缓冲区的代码合并到此class中是合适的。也许后台缓冲区和 flip()
都可以设为私有。要记住的关键是 class 中的任何内容都不应该对读取热缓冲区感兴趣。那是给外部代码来处理的。如果这样做了,这个 class 的目的就变成了提供热缓冲区。
我有以下问题
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
变量的名称,因此将访问函数命名为 hot
和 back
可能就足够了,这当然意味着重命名私有数据成员。)界面可能需要改进。要点是您添加了一个抽象层,以便 接口 在适当的时候应用 const
,而不是实现。
注:可能将填充后台缓冲区的代码合并到此class中是合适的。也许后台缓冲区和 flip()
都可以设为私有。要记住的关键是 class 中的任何内容都不应该对读取热缓冲区感兴趣。那是给外部代码来处理的。如果这样做了,这个 class 的目的就变成了提供热缓冲区。