And*_*dyG 12 c++ memory-management c++11
假设我有一些任意的类,A:
class A {
//... stuff
};
Run Code Online (Sandbox Code Playgroud)
我想调用一个外部API,它接受一个类型的共享指针,就像这样(我不能改变这个接口):
//...much later
void foo(std::shared_ptr<A> _a){
//operate on _a as a shared_ptr
}
Run Code Online (Sandbox Code Playgroud)
但是,在我正在使用的(遗留)代码中,我正在使用的类A实例被分配在堆栈上(我无法解决):
A a;
//...some stuff on a
//Now time to call foo
Run Code Online (Sandbox Code Playgroud)
除此之外,A类的实例非常大,每个实例大约1 GB.
我知道我可以打电话
foo(std::make_shared<A> a);
Run Code Online (Sandbox Code Playgroud)
但这会为A副本分配内存,我真的很想避免.
有没有办法将一些调用std::make_shared(可能是move语义)一起破解,这样我就不会被迫为另一个A类实例分配内存?
我尝试过这样的事情:
foo(std::make_shared<A>(std::move(a)));
Run Code Online (Sandbox Code Playgroud)
但据我所知,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;
}
Run Code Online (Sandbox Code Playgroud)
默认值
42
移动
43
42
移动
43
44
Ker*_* SB 18
shared_ptr对于允许"具有非空存储指针的空实例" 的构造函数,这是可能的:
A x;
std::shared_ptr<A> i_dont_own(std::shared_ptr<A>(), &x);
Run Code Online (Sandbox Code Playgroud)
(这是cppreference文档中的"overload(8)" .)
如果你知道你传递给的共享指针foo()不会被存储,复制等,即不会比你的对象寿命更长,你可以std::shared_ptr使用空删除器指向堆栈上的对象:
void emptyDeleter( A * ) {}
A a;
foo( std::shared_ptr<A>( &a, emptyDeleter ) );
Run Code Online (Sandbox Code Playgroud)
你需要再次确保共享指针或它的副本不会比对象更长,并且很好地记录了这个hack.
假设类A支持移动语义,请执行以下操作:
std::shared_ptr<A> newA = make_shared<A> (std::move (_a));
Run Code Online (Sandbox Code Playgroud)
不要再使用_a了,只能使用newA.您现在可以传递newA给该功能.
如果类A不支持移动语义,则没有安全/理智的方法来执行此操作.任何黑客只会发生工作,并可能在未来破裂.如果您控制了足够的类代码,则可以添加对移动语义的支持.
但据我所知,仍然创建了一个新的A实例.
你为什么在乎?您要避免的是复制实例中的所有数据,这样做.
移动语义的关键是将数据从一个实例移动到另一个实例,而不必进行分配/复制/释放.当然,这会使原始实例"空",所以不要再使用它了.
| 归档时间: |
|
| 查看次数: |
2448 次 |
| 最近记录: |