假设我有一些任意的类,A:
class A {
//... stuff
};
我想调用一个外部API,它接受一个类型的共享指针,就像这样(我不能改变这个接口):
//...much later
void foo(std::shared_ptr<A> _a){
//operate on _a as a shared_ptr
}
但是,在我正在使用的(遗留)代码中,我正在使用的类A
实例被分配到堆栈中(我无法解决):
A a;
//...some stuff on a
//Now time to call foo
除此之外,A类的实例非常大,每个实例大约1 GB。
我知道我可以打电话
foo(std::make_shared<A> a);
但是这会为A的副本分配内存,我真的很想避免。
有没有办法将对std::make_shared
的一些调用(可能带有move
语义)一起破解,这样我就不会被迫为另一个A类实例分配内存?
我尝试过这样的事情:
foo(std::make_shared<A>(std::move(a)));
但据我所知,仍然会创建A
的新实例。
#include <iostream>
#include <memory>
using namespace std;
class A{
public:
A(int _var=42) : var(_var){cout << "Default" << endl;}
A(const A& _rhs) : var(_rhs.var){cout << "Copy" << endl;}
A(A&& _rhs) : var(std::move(_rhs.var)){cout << "Move" << endl;}
int var;
};
void foo(std::shared_ptr<A> _a){
_a->var = 43;
cout << _a->var << endl;
}
int main() {
A a;
cout << a.var << endl;
foo(std::make_shared<A>(std::move(a)));
cout << a.var << endl;
a.var = 44;
foo(std::make_shared<A>(std::move(a)));
cout << a.var << endl;
return 0;
}
默认值
移动
车辆43
42
答案 0 :(得分:18)
使用shared_ptr
构造函数可以实现“带有非空存储指针的空实例”:
A x;
std::shared_ptr<A> i_dont_own(std::shared_ptr<A>(), &x);
(cppreference documentation上的“重载(8)”。)
答案 1 :(得分:7)
如果你知道你传递给foo()
的共享指针不会被存储,复制等,即不会比你的对象寿命更长,你可以使std::shared_ptr
指向堆栈上带有空删除器的对象:< / p>
void emptyDeleter( A * ) {}
A a;
foo( std::shared_ptr<A>( &a, emptyDeleter ) );
同样,你需要确保共享指针或它的副本不会比对象更长,并且很好地记录了这个黑客。
答案 2 :(得分:5)
假设类A
支持移动语义,请执行以下操作:
std::shared_ptr<A> newA = make_shared<A> (std::move (_a));
不要再使用_a
,仅使用newA
。您现在可以将newA
传递给该函数。
如果类A
不支持移动语义,则没有安全/理智的方法来执行此操作。任何黑客只会发生工作,并可能在未来破裂。如果您控制了足够的类代码,则可以添加对移动语义的支持。
但据我所知,仍然会创建一个新的A实例。
为什么要关心?你要避免的是复制所有实例中的数据,这样就可以了。
移动语义的意思是将数据从一个实例移动到另一个实例,而不必进行分配/复制/免费。当然,这会使原始实例“空”,所以不要再使用它了。