[英]Correct way to use std smart pointers to ensure ptr safety
這是使用std智能指針確保ptr安全的正確方法
這個例子可能不是最好的,但我試圖模仿一些真正的代碼。 我遇到的問題是在實際代碼中,通信器指針是一個原始指針,可以在任何時刻解除分配 - 導致使用指針崩潰。
所以我決定查看std :: shared_ptr和std :: weak_ptr以了解它應該如何設計現在我們有C ++ 11。 我在發送代碼中使用weak_ptr來檢查ptr是否仍然有效,然后才會取消引用ptr。 這段代碼是正確的方法嗎? 有什么改進?
#include <memory>
#include <iostream>
#include <string>
class communicator
{
public:
communicator(const char* name, int comport, int speed) : name_(name), comport_(comport), speed_(speed) { }
void send(const std::string& s) {
std::cout << "sending " << s << " using " << name_ << " at " << speed_ << " rate and using com port " << comport_ << '\n';
}
private:
const char* name_;
int comport_;
int speed_;
};
class sender
{
public:
sender() {}
void set_communicator(std::weak_ptr<communicator> comms) {
comms_ = comms;
}
void send(const std::string& s)
{
if (auto sh = comms_.lock())
sh->send(s);
else
std::cout << "Attempting to send: " << s << " but ptr no longer exists\n";
}
private:
std::weak_ptr<communicator> comms_;
};
int main() {
sender mysender;
{
// create comms object
std::shared_ptr<communicator> comms(new communicator("myname", 3, 9600));
mysender.set_communicator(comms);
mysender.send("Hi guys!");
} // comms object gets deleted here
mysender.send("Hi guys after ptr delete!");
}
輸出:
sending Hi guys! using myname at 9600 rate and using com port 3
Attempting to send: Hi guys after ptr delete! but ptr no longer exists
可以在任何時刻解除分配的指針 - 導致使用指針時崩潰
這是引入weak_ptr
的理由背后的症狀; 因此,我認為你的基於weak_ptr
的方法是正確的。
然而,我發現有爭議的是與此相關
sender() : comms_() {}
void set_communicator(std::weak_ptr<communicator> comms) {
comms_ = comms;
}
排序的最的的兩階段建設sender
的內部資產comms_
你沒有內部資產的狀態重置后施工狀態,一旦鎖()中失敗
void send(const std::string& s)
但這本身並不是“錯誤的”; 它只是可以考慮用於全尺寸應用程序的東西。
另一件事是當lock()
失敗時你不會throw
(或者拋出shared_ptr(weak_ptr)
ctor(#11) ),只是if-else
處理它。 我不知道您的完整應用程序的要求,但根據您組裝的提取,基於異常的錯誤處理將改善設計imo。
例如:
#include <memory>
#include <stdexcept>
#include <iostream>
#include <string>
class communicator
{
public:
communicator(const char* name, int comport, int speed)
: name_(name), comport_(comport), speed_(speed) { }
void send(const std::string& s) {
std::cout << "sending " << s << " using " << name_ << " at "
<< speed_ << " rate and using com port " << comport_
<< '\n';
}
private:
const char* name_;
int comport_;
int speed_;
};
class sender
{
public:
struct invalid_communicator : public std::runtime_error {
invalid_communicator(const std::string& s) :
std::runtime_error(
std::string("Attempting to send: \"") + s
+ "\" but communicator is invalid or not set"
) {}
};
sender() : comms_() {}
void set_communicator(std::weak_ptr<communicator> comms) {
comms_ = comms;
}
/* non-const */
void send(const std::string& s) throw (invalid_communicator)
{
try {
auto sh = std::shared_ptr<communicator>(comms_);
sh->send(s);
} catch (const std::bad_weak_ptr& e) {
comms_ = decltype(comms_)();
throw invalid_communicator(s);
}
}
private:
std::weak_ptr<communicator> comms_;
};
int main() {
int rv = -1;
sender mysender;
for (auto com : {1, 2, 3}) {
try {
{
// create comms object
auto comms = std::make_shared<communicator>(
"myname", com, 9600
);
mysender.set_communicator(comms);
mysender.send("Hi guys!");
}// comms object gets deleted here
mysender.send("Hi guys after ptr delete!");
// never reached in this example; just to illustrate
// how the story could continue
rv = EXIT_SUCCESS;
break; // it'd be not nice to "break", but I did not want to
// introduce another state variable
} catch (const sender::invalid_communicator& e) {
std::cerr << e.what() << std::endl;
}
}
return rv;
}
住一個Coliru's
這是使用std智能指針確保ptr安全的正確方法
除了decltype_auto所提到的內容之外,我可以補充一點,使用weak_ptr的原因是防止循環依賴。 如果不存在這種可能性,你也可以讓它共享,這會使發送的實現更不容易出錯,除非通信通道的生命周期真的是暫時的。
您可以隱藏它們在實現中存在各種連接或會話的事實。
此外,在使用標准智能指針設計接口/ API時,請考慮使用更為受限制的指針,如unique_pointer。
這樣的指針非常清楚地傳達意圖 - 例如,通過將唯一指針作為函數的參數,您可以清楚地告訴用戶他正在將指向資源的所有權交給被調用函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.