我的代码中出现以下情况:
#include <memory>
struct X
{
int i;
};
std::shared_ptr<const X> getProtoX();
void modifyX(X&);
void consumeX(const X&);
void suboptimal(bool condition)
{
std::shared_ptr<const X> x = getProtoX();
X copy(*x);
if (condition)
modifyX(copy);
consumeX(copy);
}
请注意,getProtoX()
返回一个指向常量的指针!
我们从某个地方得到一个const
对象,并希望将其不做任何修改地传递或传递修改后的副本。 consumeX
不在乎它是接收原始副本还是修改后的副本,只关心所包含的值就是应该的值。即使X
为false并且不需要复制,以上代码也始终复制condition
。
在condition == false
时,我想避免这种不必要的复制,但是我想不出一种方法来取悦我:https://godbolt.org/z/YGLVxT
看看,如果getProtoX()
返回了std::shared_ptr<X>
,任务将很容易:
std::shared_ptr<X> x = getProtoX();
if (condition)
{
x = std::make_shared<X>(*x);
modifyX(*x);
}
consumeX(*x);
这是我要在代码中表达的控制流。但是,一旦我们添加了const-correctness,我们就会由于开销过多或混合而导致开销或完全掩盖意图const
,范围和生命周期管理约束。
我觉得在const正确的情况下应该有一种干净的方法来执行此操作,而没有像立即调用的lambda这样的语法杂技或将操作移到单独的函数中,但是我找不到它。请注意,应该只有一个consumeX
调用,并且它应该停留在函数范围内(在示例代码中对此进行编码会造成混乱,并提示我不在乎的其他解决方法)。 / p>
答案 0 :(得分:5)
students
答案 1 :(得分:1)
当condition
为假时the existing solution为最佳,而X
为true时,它在堆上分配一个condition
对象。要在堆栈上分配X
:
假设构造一个X
对象并不昂贵,则可以执行以下操作:
std::shared_ptr<const X> x = getProtoX();
X modified;
if (condition)
{
modified = *x;
modifyX(modified);
}
X const& desired = condition ? modified : *x;
consumeX(desired);
这样做的缺点是无论X
为何,都构造一个新的condition
对象。
无需构造即可在堆栈上分配内存:
std::aligned_storage_t<sizeof(X), alignof(X)> modified_mem;
X* modified;
if (condition)
{
modified = new(&modified_mem) X(*x);
modifyX(*modified);
}
X const& desired = condition ? *modified : *x;
consumeX(desired);
if (condition) modified->~X();
但这很复杂。