我试图确保由shared_ptr
包裹的对象是活动的,只要通过将其作为值传递来执行函数即可。但是在函数内部根本不使用该对象,因此我只想将其用于“固定”:
void doSomething(std::shared_ptr<Foo>) {
// Perform some operations unrelated to the passed shared_ptr.
}
int main() {
auto myFoo{std::make_shared<Foo>()};
doSomething(std::move(myFoo)); // Is 'myFoo' kept alive until doSomething returns?
return 0;
}
我确实在不同的优化级别(GCC)上检查了该行为,看来它可以按预期工作,但是我不知道编译器在某些情况下是否仍可以对其进行优化。
答案 0 :(得分:6)
您不必担心-保证调用站点上的函数参数的生命周期能够在函数调用后继续存在。 (这就是为什么foo(s.c_str())
之类的std::string s
可以正常工作的原因。)
不允许编译器违反该规则,就像规则一样灵活。
答案 1 :(得分:1)
这很大程度上取决于doSomething
和Foo
的主体实际外观。例如,考虑以下示例:
struct X
{
~X() { std::cout << "2"; };
};
void f(std::shared_ptr<X>) { std::cout << "1"; }
int main()
{
auto p = std::make_shared<X>();
f(std::move(p));
}
此程序具有与以下相同的可观察效果:
int main()
{
std::cout << "12";
}
和顺序"12"
得到保证。因此,在生成的程序集中,可能没有共享的指针被使用。但是,由于内部涉及动态内存分配和虚拟函数调用,因此大多数编译器可能不会执行这种积极的优化,而优化起来就不那么容易了。
答案 2 :(得分:0)
如果内联函数并且复制没有副作用,则编译器可以优化将对象复制到函数参数中的过程。
复制shared_ptr
会增加其引用计数,因此它确实有副作用,因此编译器无法对其进行优化(除非编译器可以向自己证明不修改引用计数对程序没有影响)