智能指针是否被视为指针?因此,它们可以隐式用作指针吗?
假设我有以下类(class):
class MyClass {
//...
std::shared_ptr<AnotherClass> foo() { /*whatever*/ };
void bar(AnotherClass* a) { /*whatever too*/ };
//...
}
然后可以通过以下方式使用
MyClass
吗?// m is an instance of MyClass
m.bar(m.foo());
最佳答案
没有!这将是糟糕的API 。是的,您可以轻松地在shared_ptr
中实现它,但这仅仅是因为您不意味着应该这样做。
为什么这是一个坏主意? bar
的基于纯指针的接口(interface)不保留共享指针的实例。如果bar
碰巧将原始指针存储在某个地方然后退出,则没有任何东西可以保证它存储的指针将来不会悬空。保证的唯一方法是保留共享指针的实例,而不是原始指针(这就是shared_ptr
的全部内容!)。
更糟糕的是:如果foo()
返回的指针实例在返回foo()
时仅具有一个引用(例如,如果foo
是新对象的简单工厂),则以下代码是未定义的行为:
AnotherClass *ptr = m.foo().get();
// The shared_ptr instance returned by foo() is destroyed at this point
m.bar(ptr); // undefined behavior: ptr is likely a dangling pointer here
这里是选项;在考虑其继任者之前,请先考虑前面列出的那些。
bar(AnotherClass *)
是一个外部API,则需要以安全的方式包装它,即原本应调用Original::bar
的代码应调用MyWrapped::bar
,并且包装程序应执行必要的生命周期管理。假设存在startUsing(AnotherClass *)
和finishUsing(AnotherClass *)
,并且代码期望指针在startUsing
和finishUsing
之间保持有效。您的包装器将是:class WithUsing {
std::unique_ptr<AnotherClass> owner; /* or shared_ptr if the ownership is shared */
std::shared_ptr<User> user;
public:
WithUsing(std::unique_ptr<AnotherClass> owner, std::Shared_ptr<User> user) :
owner(std::move(owner)), user(std::move(user)) {
user.startUsing(owner.get());
}
void bar() const {
user.bar(owner.get());
}
~WithUsing() {
user.finishUsing(owner.get());
}
};
然后,您将使用
WithUsing
作为User
对象的句柄,并且任何使用都将通过该句柄进行,以确保该对象的存在。 AnotherClass
是可复制的并且复制非常便宜(例如,它由一个或两个指针组成),则按值传递它:void bar(AnotherClass)
bar
的实现不需要更改值,则可以将其定义为采用const值(声明可以没有const
,因为在那里没有关系):void bar(const AnotherClass a) { ... }
bar
不存储指针,则不要将其传递给指针:默认情况下传递const引用,或在必要时传递非const引用。void bar(const AnotherClass &a);
void bar_modifies(AnotherClass &a);
bar
是有意义的,则:AnotherClass
是可以的,则使用std::optional
:void bar(std::optional<AnotherClass> a);
AnotherClass
拥有所有权,则传递unique_ptr
可以正常进行,因为它可以为null。 shared_ptr
可以正常工作,因为它可以为null。 foo()
创建了一个新对象(相对于返回一个已经存在的对象),则无论如何它应该返回unique_ptr
,而不是shared_ptr
。工厂函数应该返回唯一的指针:这是惯用的C++。否则会造成困惑,因为返回shared_ptr
意味着表示现有的共享所有权。std::unique_ptr<AnotherClass> foo();
bar
应该拥有该值的所有权,那么它应该接受一个唯一的指针-这是“我正在接管该对象的寿命”的惯用法:void bar(std::unique_ptr<const AnotherClass> a);
void bar_modifies(std::unique_ptr<AnotherClass> a);
bar
应该保留共享所有权,那么它应该采用shared_ptr
,您将立即将从unique_ptr
返回的foo()
转换为共享的:struct MyClass {
std::unique_ptr<AnotherClass> foo();
void bar(std::shared_ptr<const AnotherClass> a);
void bar_modifies(std::shared_ptr<AnotherClass> a);
};
void test() {
MyClass m;
std::shared_ptr<AnotherClass> p{foo()};
m.bar(p);
}
shared_ptr(const Type)
和shared_ptr(Type)
将共享所有权,它们分别提供对象的恒定 View 和可修改 View 。
shared_ptr<Foo>
也可以转换为shared_ptr<const Foo>
(但是反之则不行,您应该使用const_pointer_cast
(谨慎)。您应该始终默认将对象作为常量访问,并且仅在有明确需要时才使用非常量类型它。如果某个方法没有修改任何东西,则通过让它接受对
const something
的引用/指针来使其自身记录该事实。关于c++ - 智能指针可以隐式用作指针吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58308058/