引言
考虑以下c++
代码:
void emplace(shared_ptr<string_view>& sv,function<void(void)>&& func){
// sv == nullptr ???
}
int main(){
auto sv = make_shared<string_view>("123");
emplace(sv,[sv{move(sv)}](){ });
}
上述代码有安全隐患,您能看出来么?
下面是展开代码
void emplace(std::shared_ptr<std::basic_string_view<char, std::char_traits<char> > > & sv, std::function<void ()> && func)
{}
int main()
{
std::shared_ptr<std::basic_string_view<char, std::char_traits<char> > > sv = std::make_shared<std::basic_string_view<char, std::char_traits<char> >>("123");
class __lambda_11_16
{
std::shared_ptr<std::basic_string_view<char, std::char_traits<char> > > sv;
public:
inline /*constexpr */ void operator()() const
{
}
// inline __lambda_11_16(const __lambda_11_16 &) noexcept = default;
// inline __lambda_11_16(__lambda_11_16 &&) noexcept = default;
public: __lambda_11_16(std::shared_ptr<std::basic_string_view<char, std::char_traits<char> > > _sv)
: sv{_sv}
{}
};
emplace(sv, std::function<void ()>(__lambda_11_16{std::shared_ptr<std::basic_string_view<char, std::char_traits<char> > >(std::move(sv))}));
}
首先可以看到并不是lambda
函数导致的奇怪问题.
其实在我们书写函数时,包含了隐藏的执行顺序
- 拷贝
string_view
- 构造
lambda
但是凑巧的是,在gcc上,参数表达式是从右向左计算的.实际执行顺序与期望相反.参数1指向了一个被move
过的指针,所以参数1为nullptr
.
标准中未定义标准的调用顺序,因此应当分步书写(即手动声明调用先后顺序),或者在此情况下复制智能指针而不是移动它.