![](/img/trans.png)
[英]Why 'std::make_shared' is always using the global memory allocation even with class overloaded new/delete operators?
[英]How to avoid big memory allocation with std::make_shared
假設我有一些任意的類,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;
}
默認
42
移動
43
42
移動
43
44
這可以通過shared_ptr
構造函數實現,該構造函數允許“具有非空存儲指針的空實例”:
A x;
std::shared_ptr<A> i_dont_own(std::shared_ptr<A>(), &x);
(這是cppreference文檔中的“overload(8)”。)
如果你知道你傳遞給foo()
共享指針不會被存儲,復制等,即不會比你的對象更活躍,你可以使std::shared_ptr
指向堆棧上帶有空刪除器的對象:
void emptyDeleter( A * ) {}
A a;
foo( std::shared_ptr<A>( &a, emptyDeleter ) );
你需要再次確保共享指針或它的副本不會比對象更長,並且很好地記錄了這個hack。
假設類A
支持移動語義,請執行以下操作:
std::shared_ptr<A> newA = make_shared<A> (std::move (_a));
不要再使用_a
了,只使用newA
。 您現在可以將newA
傳遞給該函數。
如果A
類不支持移動語義,則沒有安全/理智的方法來執行此操作。 任何黑客只會發生工作,並可能在未來破裂。 如果您控制了足夠的類代碼,則可以添加對移動語義的支持。
但據我所知,仍然創建了一個新的A實例。
你為什么在乎? 您要避免的是復制實例中的所有數據 ,這樣做。
移動語義的關鍵是將數據從一個實例移動到另一個實例,而不必進行分配/復制/釋放。 當然,這會使原始實例“空”,所以不要再使用它了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.