有条件地传递修改后的副本而不是const original变得很丑

时间:2019-07-30 16:13:09

标签: c++

我的代码中出现以下情况:

#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>

2 个答案:

答案 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();

但这很复杂。