正确使用std智能指针以确保ptr安全
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 existsn";
}
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的
这是使用std智能指针来确保ptr安全的正确方法吗
除了decltype_auto提到的之外,我还可以补充一点,使用weak_ptr的原因之一是为了防止循环依赖。如果这种可能性不存在,您还可以将其共享,这将使send的实现不太容易出错,除非通信通道的寿命确实是暂时的。
您可以隐藏它们在实现中存在各种连接或会话的事实。
此外,在使用标准智能指针设计接口/API时,请考虑使用更受限制的指针,如unique_pointer。
这样的指针非常清楚地传达意图——例如,通过将一个唯一的指针作为函数的参数,您可以清楚地告诉用户,他正在将指向的资源的所有权交给被调用的函数。
- 如何确保C++函数在定义之前声明(如override关键字)
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- CLANG 编译器 说:变量"PTR"可能未初始化
- 使用Unique_ptr确保工厂中的对象唯一
- MESI协议和std::atomic-它是否确保所有写入立即对其他线程可见?
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 确保流程关闭
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 如何确保接受的C++模板类型使运算符重载?
- 确保编译时的特定 std::array 位置
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- C++ 确保子类为常量提供自定义值
- 确保内存映射页位于内存中
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 确保套装新鲜度的有效方法
- C ++类型特征:确保子类实现方法
- 正确使用std智能指针以确保ptr安全