在以下代碼示例中:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo *foo){
auto my_foo = std::shared_ptr<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(new Foo());
return 0;
}
我是否需要清理main()由bar.addFoo(new Foo)呼叫創建的指標,還是會由Bar創建shared_ptr它的指標來處理?我的理解是,auto my_foo = std::shared_ptr<Foo>(foo);將使用復制建構式將這個指標復制到my_foo離開原來的懸空狀態,對嗎?
uj5u.com熱心網友回復:
建構式采用原始指標的想法是將所有權傳遞給std::shared_ptr。因此,不,您不必delete將原始指標傳遞給std::shared_ptr. 這樣做會導致雙重洗掉,即UB。
請注意,通常傳遞原始指標是危險的。考慮以下更通用的示例:
void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}
如果在my_foo構造之前拋出例外,foo則會泄漏。
如果您沒有特殊原因傳遞原始指標,請考慮以下替代方案:
class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};
int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}
在這里,您傳遞引數(如果有)以Foo在內部構造addFoo()而不是Foo在呼叫addFoo().
args...如果需要,可以使用完美轉發:
template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}
uj5u.com熱心網友回復:
原始指標不會終止生命周期,但共享指標會。當您從原始指標創建共享指標時,共享指標將獲得物件的所有權。這意味著當指向它的最后一個共享指標超出范圍時,該物件將被銷毀。
在您的代碼中,my_foo獲取使用創建的物件的所有權,回傳new Foo()時超出范圍addFoo,并且由于它包含唯一的共享參考,因此正確地銷毀了物件。
uj5u.com熱心網友回復:
你寫的代碼是正確的。但在現代C ,你不應該使用原始指標,new并且delete除非你有代碼,不會進行互操作。如果您可以提供幫助(如果問題評論有任何指示,您可以),請始終使用智能指標:
#include <iostream>
#include <memory>
class Foo {};
class Bar {
public:
void addFoo(std::unique_ptr<Foo> foo) {
auto my_foo = std::shared_ptr<Foo>(std::move(foo));
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_unique<Foo>());
return 0;
}
上面,addFoo成員函式接收指標作為 a unique_ptr,并用于std::move將指標的所有權從 轉移unique_ptr到 ,shared_ptr而不復制所指物件;在構造 之后shared_ptr,unique_ptr處于空狀態。您也可以直接addFoo接收shared_ptr,或在成員函式內就地構造物件,如 Evg 的回答。
使用unique_ptr而不是原始指標清楚地表明該方法打算獲得分配的所有權,并鼓勵呼叫者自己使用智能指標,從而減少他們delete以后忘記分配的可能性。
uj5u.com熱心網友回復:
正確的 C 方法是這樣的:
#include <iostream>
class Foo{
};
class Bar{
public:
void addFoo(Foo foo){
auto my_foo = std::make_shared<Foo>(foo);
}
};
int main() {
auto bar = Bar();
bar.addFoo(Foo());
return 0;
}
這避免了任何原始指標或裸新,并且是完全例外安全的。此外,還std::make_shared引入了一些性能優勢。這里的一個令人困惑的事情是代碼似乎不必要地復制了Foo物件,但是,由于 C 17,由于回傳值優化(RVO),您可以保證根本沒有副本(Foo作為引數傳遞給addFoo)。
uj5u.com熱心網友回復:
您可以使用 make_shared 創建共享指標。如果你想在 main 中構造 Foo (例如因為你有可用的引數),那么在構造點使用 make_shared 并傳遞 shared_ptr 。
#include <iostream>
class Foo{
~Foo() { std::cout << "Foo destructed" << std::endl; }
};
class Bar{
public:
void addFoo(std::shared_ptr<Foo> foo){
auto my_foo = foo;
}
};
int main() {
auto bar = Bar();
bar.addFoo(std::make_shared<Foo>());
return 0;
}
delete 還會呼叫您的解構式。您可以通過列印一條訊息來測驗共享指標是否會破壞您的物件或是否需要洗掉。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/402515.html
標籤:
