【发布时间】:2014-12-10 12:39:23
【问题描述】:
让我们看一个现实生活中的例子:
class RuleNameConverter {
public:
RuleNameConverter(const boost::property_tree::ptree& pt);
int toIdentifier(const std::string& name) const;
std::string toName(const int id) const;
private:
using Bimap = boost::bimap<std::string, int>;
Bimap bimap_;
};
构造函数在哪里:
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) {
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
bimap_.insert(Bimap::value_type { name, id });
}
}
}
假设你想要一个 const 成员属性:
...
const Bimap bimap_;
};
你必须在初始化列表中初始化它,而不是在构造函数体中。它的初始化很重要,所以你必须委托一个函数来计算它的值。您可以使用 lambda 返回的值,利用移动语义(没有临时对象的副本):
RuleNameConverter::RuleNameConverter(const boost::property_tree::ptree& pt) :
bimap_ { [&pt]() {
Bimap results;
for (const auto& item : pt) {
if (item.first == "rule") {
auto name = item.second.get < std::string > ("<xmlattr>.name");
auto id = item.second.get<int>("<xmlattr>.id");
results.insert(Bimap::value_type {name, id});
}
}
return results;
}() } {
}
使用这种技术有什么缺点吗?值得麻烦吗?我觉得它的可读性稍差,但性能呢?
【问题讨论】:
-
嗯。我会仔细检查捕获范围规则,以确保那里没有怪癖(你处于一个奇怪的环境中)——可能不是,在 2 个标准修订之后,尤其是在实践中。
-
将
return results;更改为return std::move(results);。是的,编译器有 RVO,但这种方式很冗长。 -
@GreenScape 我记得 C++11 标准在这种情况下需要 RVO,对吧?
-
C++11 不需要 RVO,但如果不执行 RVO,它确实需要尝试使用移动构造函数。绝对没有理由写
return std::move(results);。 -
@hvd,在
return results;中究竟是如何调用移动运算符的?
标签: c++ c++11 lambda initializer-list