我应该使用 unique_ptr 作为字符串吗?
Posted
技术标签:
【中文标题】我应该使用 unique_ptr 作为字符串吗?【英文标题】:Should I use unique_ptr for a string? 【发布时间】:2018-02-09 11:12:09 【问题描述】:我是 C++ 新手。我听说使用unique_ptr
/ shared_ptr
是引用在堆上分配的数据的“必经之路”。因此,使用unique_ptr
s 代替std::string
s 有意义吗?
【问题讨论】:
为什么?为什么需要指向std::string
的指针?
不,std::string
本身就足够聪明。
这些答案值得一读:***.com/questions/7657718/…
为什么人们投票结束这个作为“不清楚你在问什么”?这个问题有什么不清楚的地方?
您可以在与使用unique_ptr<int>
相同的情况下使用unique_ptr<string>
。我无法想象这样的情况......但如果出现正确的情况,那么unique_ptr<string>
将比string*
原始指针好得多。
【参考方案1】:
你为什么要这样做?
std::string 对象自己管理“包含”字符串(内存字节)的生命周期。
因为您是 C++ 新手。在您的函数/类方法中,我建议您在堆栈上创建对象: 像这样:
std::string s;
相对于使用堆:
std::string* s = new std::string();
当您的对象超出范围时,在堆栈上创建的对象将被销毁。所以不需要智能指针。
您可以点击此链接了解更多信息:http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/
【讨论】:
> 一个 std::string 对象自己管理一个字符串的生命周期。这个信息真的很有帮助,而且我虽然std::string
是一门课。谢谢!
字符串对象不管理生命周期。它管理资源。字符串对象的生命周期由语言管理。 C++ 标准也没有提及术语“堆栈”,因为您正在使用它。您将实现细节与更广泛的概念混淆了:具有自动存储持续时间的对象。 @AkiraKido:std::string
是 一个类(嗯,具体类模板实例化的别名)。不过,我不知道,为什么这会有所作为。
@IInspectable 谢谢。我明白你的意思。但是,我没有混淆任何东西。我理解了这个问题,这是解释它的最简单方法。可以看链接:learncpp.com/cpp-tutorial/79-the-stack-and-the-heap
有一些简单的方法来定义概念,不需要使用错误或误导性的术语。您正在使用错误的术语(我之前指出了 2 个实例)。您可能会发现这是在吹毛求疵,但是一旦您使用了 C++ 一段时间,您就会明白准确性的至关重要的重要性。这个建议的答案不准确。
@IInspectable 我试图从你的角度来看事情。无论如何,我的评论并没有误导(如果你从我的角度看的话)。问题的基础是关于指针;和指针指向内存。我相信使用堆和堆栈内存分配(在 C++ 中)来解释解决方案是最简单的方法。你能更容易地解决这个问题吗?您可以添加评论以提供帮助;我认为这比侮辱更需要。【参考方案2】:
std::string
无需使用 std::unique_ptr
或 std::shared_ptr
。
您不必为简单的std::string
分配内存。
std::string str = "abc";
就这么简单。无需分配内存,因为std::string
自己管理“真实”字符串。
有些情况可能会导致使用指针,尽管它可能是类/结构实例。
例如考虑使用
std::unique_ptr<MyClass> p;
而不是
MyClass *p;
如果可能的话。
【讨论】:
【参考方案3】:您通常不需要指向字符串的指针,就像您通常不需要指向整数的指针一样。您可以只存储字符串值,也可以传递字符串值等。
但是,如果您处于需要指向字符串的指针的特殊情况,那么是的,std::unique_ptr<std::string>
或 std::shared_ptr<std::string>
比 std::string*
更好。
【讨论】:
除非指针代表一个非拥有指针被传递给一个函数,并且它可能为空。 @MartinBonner:有 C++17std::optional<std::string>
,对于那些没有 C++17 的人,请参阅 Boost。但我忽略了它,因为它几乎肯定不需要。几乎没有什么情况需要区分空字符串和无字符串。
是的。在std::string
的具体情况下,需要区分空和不存在是非常深奥的。我在考虑更一般的情况。
但是有一个关于所有权的一般原则。智能指针只会更好地拥有资源。他们并不擅长管理他们不拥有的资源。所以智能指针不能与原始指针互换,因此一个比另一个更好。它们只是用于不同的目的。
@MSalters 我的主要观点是它不是智能指针和原始指针之间的“非此即彼”。在某些情况下,每个都是最好的。如果您告诉人们始终使用智能指针,他们会尝试使用unique_ptr
,而在这不起作用的地方,他们会使用shared_ptr
来处理其他所有内容。这不是一个好习惯。【参考方案4】:
std::unique_ptr
确保指向的对象不会被意外复制和正确删除。
由于您应该尽可能避免动态分配,您可以简单地将std::string
保留为您的班级成员。如果它是一个返回值,正如已经指出的那样,字符串类足够聪明,可以以安全的方式正确移动资源。
您不需要保证字符串是唯一的,我的意思是,不存在副本,所以唯一的 ptr 只是一个太强的约束。
KIS 规则:保持简单。
【讨论】:
【参考方案5】:通常,默认情况下,答案是否定的,正如其他人所建议的那样。然而——有时,答案可能自相矛盾地是“可能是”!怎么会?
使用std::string
,您无法控制分配缓冲区的方式、时间和人员。虽然如果您使用不同的分配器 (std::basic_string<char, MyAllocatorType>
) 会有所缓解 - 结果类是 not std::string
;并且通常不会被采用std::string
的函数所接受。仅仅为了这个目的而使用分配器可能没有意义。
更具体地说,您可以允许将基于唯一指针的字符串类创建为现有缓冲区的所属包装器。
现在我们可以使用string_view
's - 它们甚至在 C++20 的标准中 (std::string_view
) - 您不必为基于唯一指针的字符串重写整个字符串类;您只需要使用原始指针和以字节为单位的大小(或大小 - 1,如果您想要更好的空终止安全性)创建一个字符串视图。如果您仍然想要 std::string 方法,它们'将是单行的,例如
std::string_view view() const
return std::string_viewuptr_.get(), size_;
substr(size_type pos = 0, size_type count = npos) const
return view().substr(pos, count);
如果您想就地更新字符串,同时保持其大小 - std::string
不适合您:要么它完全不变,要么在大小和内容上都是可变的。
【讨论】:
以上是关于我应该使用 unique_ptr 作为字符串吗?的主要内容,如果未能解决你的问题,请参考以下文章
unique_ptr 到派生类作为函数的参数,该函数将 unique_ptr 带到基类