C++ 初始化,根据条件进行复制或使用引用

C++ Initialization by making a copy or using reference depending on the condition

提问人:np_king 提问时间:4/8/2021 最后编辑:Remy Lebeaunp_king 更新时间:4/8/2021 访问量:91

问:

І 有一个名为 的变量。booldo_copy

如果 ,我想处理一个副本,比如do_copy == true
some_type model = input_model

如果 ,我想使用引用,例如do_copy == false
some_type& model = input_model

执行我想要的代码:

some_type copy_model;
if (do_copy)
    copy_model = input_model;
some_type& model = do_copy ? copy_model : input_model;

它看起来不是很好,我调用了默认构造函数,这对于 .do_copy == false

有没有办法让它更优雅?

C++ 引用 copy-constructor

评论


答:

2赞 Woodford 4/8/2021 #1

避免不必要的构造函数的一种方法是仅在需要时动态分配:copy_model

std::unique_ptr<some_type> copy_model;
if (do_copy)
    copy_model = std::make_unique<some_type>(input_model);
some_type& model = copy_model ? *copy_model : input_model;

不过,我不确定这是否更优雅。

评论

0赞 Woodford 4/8/2021
@cigien这不是错别字,但感谢您的彻底:)
0赞 cigien 4/8/2021
哦,我明白。您正在使用转换为布尔值来检查相同的内容。我的错,请回滚到您喜欢的版本。
1赞 Remy Lebeau 4/8/2021 #2

将使用的逻辑移动到单独的函数中:model

void doSomething(some_type& model)
{
    //...
}

...

if (do_copy)
{
    some_type copy_model = input_model;
    doSomething(copy_model);
}
else
    doSomething(input_model);

演示

或者,在 C++ 11 及更高版本中:

template<typename T>
void doSomething(T&& model) // T will be lvalue-ref or rvalue-ref depending on input
{
    //...
}

...

if (do_copy)
    doSomething(some_type{input_model});
else
    doSomething(input_model);

演示

1赞 user2407038 4/8/2021 #3

您可以将副本作为三元表达式的一部分:

some_type copy_model;
some_type& model =
    do_copy
    ? (copy_model = input_model, copy_model)
    : (input_model);

即使为 false,这仍然需要默认构造。如果你的默认构造函数非常昂贵,你可以使用一个可选的:copy_modeldo_copy

std::optional<some_type> copy_model;
some_type& model =
    do_copy
    ? (copy_model = input_model, *copy_model)
    : (input_model);

请注意,这并不是完全免费的:与 相比,析构函数有一个额外的分支。std::optional<some_type>some_type

如果你发现自己需要经常这样做,为什么不把这个模式包装在一个类中呢:

template<class T>
struct copy_or_reference
{
    std::optional<T> maybeCopy;
    T& ref;

    copy_or_reference(copy_tag, T& x)
        : ref(x)
    {};

    copy_or_reference(reference_tag, const T& x)
        : maybeCopy(x), ref(*maybeCopy)
    {};

    operator T& () const { return ref; };
    operator T& () { return ref; };
};

template<class T>
auto make_copy_or_reference(bool copy, T& x)
{
    return copy ? copy_or_reference<T>(copy_tag{}, x) : copy_or_reference<T>(reference_tag{}, x);
}


void do_something(some_type&);

void do_something_else()
{
    ...
    copy_or_reference<some_type> model = make_copy_or_reference(do_copy, input_model);
    do_something(model);
}