C++智能指针简单剖析

http://blog.csdn.net/lanxuezaipiao/article/details/41603883

导读

最近在补看《C++ Primer Plus》第六版,这的确是本好书,其中关于智能指针的章节解析的非常清晰,一解我以前的多处困惑。C++面试过程中,很多面试官都喜欢问智能指针相关的问题,比如你知道哪些智能指针?shared_ptr的设计原理是什么?如果让你自己设计一个智能指针,你如何完成?等等……。而且在看开源的C++项目时,也能随处看到智能指针的影子。这说明智能指针不仅是面试官爱问的题材,更是非常有实用价值。

下面是我在看智能指针时所做的笔记,希望能够解决你对智能指针的一些困扰。

目录

  1. 智能指针背后的设计思想
  2. C++智能指针简单介绍
  3. 为什么摒弃auto_ptr?
  4. unique_ptr为何优于auto_ptr?
  5. 如何选择智能指针?

正文

1. 智能指针背后的设计思想

我们先来看一个简单的例子:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">void</span> remodel(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> & str)
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> * ps = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(str);
    ...
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">if</span> (weird_thing())
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">throw</span> exception();
    str = *ps; 
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">delete</span> ps;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span>;
}</code>

当出现异常时(weird_thing()返回true),delete将不被执行,因此将导致内存泄露。 如何避免这种问题?有人会说,这还不简单,直接在throw exception();之前加上delete ps;不就行了。是的,你本应如此,问题是很多人都会忘记在适当的地方加上delete语句(连上述代码中最后的那句delete语句也会有很多人忘记吧),如果你要对一个庞大的工程进行review,看是否有这种潜在的内存泄露问题,那就是一场灾难! 这时我们会想:当remodel这样的函数终止(不管是正常终止,还是由于出现了异常而终止),本地变量都将自动从栈内存中删除—因此指针ps占据的内存将被释放,如果ps指向的内存也被自动释放,那该有多好啊。 我们知道析构函数有这个功能。如果ps有一个析构函数,该析构函数将在ps过期时自动释放它指向的内存。但ps的问题在于,它只是一个常规指针,不是有析构凼数的类对象指针。如果它指向的是对象,则可以在对象过期时,让它的析构函数删除指向的内存。

这正是 auto_ptr、unique_ptr和shared_ptr这几个智能指针背后的设计思想。我简单的总结下就是:将基本类型指针封装为类对象指针(这个类肯定是个模板,以适应不同基本类型的需求),并在析构函数里编写delete语句删除指针指向的内存空间。

因此,要转换remodel()函数,应按下面3个步骤进行:

  • 包含头义件memory(智能指针所在的头文件);
  • 将指向string的指针替换为指向string的智能指针对象;
  • 删除delete语句。

下面是使用auto_ptr修改该函数的结果:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;"># include <memory></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">void</span> remodel (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> & str)
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> ps (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(str));
    ...
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">if</span> (weird_thing ())
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">throw</span> exception(); 
    str = *ps; 
    <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// delete ps; NO LONGER NEEDED</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span>;
}</code>

2. C++智能指针简单介绍

STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr(本文章暂不讨论)。 模板auto_ptr是C++98提供的解决方案,C+11已将将其摒弃,并提供了另外两种解决方案。然而,虽然auto_ptr被摒弃,但它已使用了好多年:同时,如果您的编译器不支持其他两种解决力案,auto_ptr将是唯一的选择。

使用注意点

  • 所有的智能指针类都有一个explicit构造函数,以指针作为参数。比如auto_ptr的类模板原型为: <code class="language-cppp hljs r" style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">templet<class <span class="hljs-literal" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">T</span>> class auto_ptr { explicit auto_ptr(X* p = <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">0</span>) ; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">...</span> };</code> 因此不能自动将指针转换为智能指针对象,必须显式调用: <code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span>> pd; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span> *p_reg = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span>; pd = p_reg; <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// not allowed (implicit conversion)</span> pd = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span>>(p_reg); <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// allowed (explicit conversion)</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span>> pshared = p_reg; <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// not allowed (implicit conversion)</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">double</span>> pshared(p_reg); <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// allowed (explicit conversion)</span></code>
  • 对全部三种智能指针都应避免的一点: <code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> vacation(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"I wandered lonely as a cloud."</span>); <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pvac(&vacation); <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// No</span></code> pvac过期时,程序将把delete运算符用于非堆内存,这是错误的。

使用举例

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <iostream></span>
<span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <string></span>
<span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <memory></span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">class</span> report
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">private</span>:
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> str;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">public</span>:
 report(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">const</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> s) : str(s) {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Object created.\n"</span>;
 }
 ~report() {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Object deleted.\n"</span>;
 }
 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">void</span> comment() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">const</span> {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << str << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"\n"</span>;
 }
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> main() {
 {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><report> ps(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> report(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"using auto ptr"</span>));
  ps->comment();
 }

 {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><report> ps(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> report(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"using shared ptr"</span>));
  ps->comment();
 }

 {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>::unique_ptr<report> ps(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> report(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"using unique ptr"</span>));
  ps->comment();
 }
 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span> <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">0</span>;
}</code>

3. 为什么摒弃auto_ptr?

先来看下面的赋值语句:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span>< <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> ps (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"I reigned lonely as a cloud.”);
auto_ptr<string> vocation; 
vocaticn = ps;</span></code>

上述赋值语句将完成什么工作呢?如果ps和vocation是常规指针,则两个指针将指向同一个string对象。这是不能接受的,因为程序将试图删除同一个对象两次——一次是ps过期时,另一次是vocation过期时。要避免这种问题,方法有多种:

  • 定义陚值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本,缺点是浪费空间,所以智能指针都未采用此方案。
  • 建立所有权(ownership)概念。对于特定的对象,只能有一个智能指针可拥有,这样只有拥有对象的智能指针的构造函数会删除该对象。然后让赋值操作转让所有权。这就是用于auto_ptr和uniqiie_ptr 的策略,但unique_ptr的策略更严格。
  • 创建智能更高的指针,跟踪引用特定对象的智能指针数。这称为引用计数。例如,赋值时,计数将加1,而指针过期时,计数将减1,。当减为0时才调用delete。这是shared_ptr采用的策略。

当然,同样的策略也适用于复制构造函数。 每种方法都有其用途,但为何说要摒弃auto_ptr呢? 下面举个例子来说明。

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <iostream></span>
<span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <string></span>
<span class="hljs-preprocessor" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">#include <memory></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">using</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">namespace</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">std</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> main() {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> films[<span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">5</span>] =
 {
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Fowl Balls"</span>)),
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Duck Walks"</span>)),
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Chicken Runs"</span>)),
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Turkey Errors"</span>)),
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"Goose Eggs"</span>))
 };
 <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pwin;
 pwin = films[<span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">2</span>]; <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// films[2] loses ownership. 将所有权从films[2]转让给pwin,此时films[2]不再引用该字符串从而变成空指针</span>

 <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"The nominees for best avian baseballl film are\n"</span>;
 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> i = <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">0</span>; i < <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">5</span>; ++i)
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << *films[i] << endl;
 <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"The winner is "</span> << *pwin << endl;
 <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cin</span>.get();

 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span> <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">0</span>;
}</code>

运行下发现程序崩溃了,原因在上面注释已经说的很清楚,films[2]已经是空指针了,下面输出访问空指针当然会崩溃了。但这里如果把auto_ptr换成shared_ptr或unique_ptr后,程序就不会崩溃,原因如下:

  • 使用shared_ptr时运行正常,因为shared_ptr采用引用计数,pwin和films[2]都指向同一块内存,在释放空间时因为事先要判断引用计数值的大小因此不会出现多次删除一个对象的错误。
  • 使用unique_ptr时编译出错,与auto_ptr一样,unique_ptr也采用所有权模型,但在使用unique_ptr时,程序不会等到运行阶段崩溃,而在编译器因下述代码行出现错误: <code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pwin; pwin = films[<span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">2</span>]; <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// films[2] loses ownership.</span></code> 指导你发现潜在的内存错误。

这就是为何要摒弃auto_ptr的原因,一句话总结就是:避免潜在的内存崩溃问题。

4. unique_ptr为何优于auto_ptr?

可能大家认为前面的例子已经说明了unique_ptr为何优于auto_ptr,也就是安全问题,下面再叙述的清晰一点。 请看下面的语句:

请看下面的语句:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> p1(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"auto"</span>) ; <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">//#1</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">auto_ptr</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> p2;                       <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">//#2</span>
p2 = p1;   </code>

在语句#3中,p2接管string对象的所有权后,p1的所有权将被剥夺。前面说过,这是好事,可防止p1和p2的析构函数试图刪同—个对象; 但如果程序随后试图使用p1,这将是件坏事,因为p1不再指向有效的数据。

下面来看使用unique_ptr的情况:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> p3 (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"auto"</span>);   <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">//#4</span>
unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> p4;                       <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">//#5</span>
p4 = p3;    </code>

编译器认为语句#6非法,避免了p3不再指向有效数据的问题。因此,unique_ptr比auto_ptr更安全。

但unique_ptr还有更聪明的地方。 有时候,会将一个智能指针赋给另一个并不会留下危险的悬挂指针。假设有如下函数定义:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> demo(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">const</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">char</span> * s)
{
    unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> temp (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (s)); 
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span> temp;
}</code>

并假设编写了如下代码:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> ps;
ps = demo(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">'Uniquely special");</span></code>

demo()返回一个临时unique_ptr,然后ps接管了原本归返回的unique_ptr所有的对象,而返回时临时的 unique_ptr 被销毁,也就是说没有机会使用 unique_ptr 来访问无效的数据,换句话来说,这种赋值是不会出现任何问题的,即没有理由禁止这种赋值。实际上,编译器确实允许这种赋值,这正是unique_ptr更聪明的地方。

总之,党程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;如果源 unique_ptr 将存在一段时间,编译器将禁止这么做,比如:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pu1(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"hello world"</span>));
unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pu2;
pu2 = pu1;                                      <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// #1 not allowed</span>
unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> pu3;
pu3 = unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span> (<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"You"</span>));   <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// #2 allowed</span></code>

其中#1留下悬挂的unique_ptr(pu1),这可能导致危害。而#2不会留下悬挂的unique_ptr,因为它调用 unique_ptr 的构造函数,该构造函数创建的临时对象在其所有权让给 pu3 后就会被销毁。这种随情况而已的行为表明,unique_ptr 优于允许两种赋值的auto_ptr 。

当然,您可能确实想执行类似于#1的操作,仅当以非智能的方式使用摒弃的智能指针时(如解除引用时),这种赋值才不安全。要安全的重用这种指针,可给它赋新值。C++有一个标准库函数std::move(),让你能够将一个unique_ptr赋给另一个。下面是一个使用前述demo()函数的例子,该函数返回一个unique_ptr<string>对象: 使用move后,原来的指针仍转让所有权变成空指针,可以对其重新赋值。

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">string</span>> ps1, ps2;
ps1 = demo(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"hello"</span>);
ps2 = move(ps1);
ps1 = demo(<span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">"alexia"</span>);
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << *ps2 << *ps1 << endl;</code>

5. 如何选择智能指针?

在掌握了这几种智能指针后,应使用哪种智能指针呢? (1)如果程序要使用多个指向同一个对象的指针,应选择shared_ptr。这样的情况包括: 有一个指针数组,并使用一些辅助指针来标示特定的元素,如最大的元素和最小的元素; 两个对象包含都指向第三个对象的指针; STL容器包含指针。 很多STL算法都支持复制和赋值操作,这些操作可用于shared_ptr,但不能用于unique_ptr(编译器发出warning)和auto_ptr(行为不确定)。如果你的编译器没有提供shared_ptr,可使用Boost库提供的shared_ptr。

(2)如果程序不需要多个指向同一个对象的指针,则可使用unique_ptr。如果函数使用new分配内存,并返还指向该内存的指针,将其返回类型声明为unique_ptr是不错的选择。这样,所有权转让给接受返回值的unique_ptr,而该智能指针将负责调用delete。可将unique_ptr存储到STL容器在那个,只要不调用将一个unique_ptr复制或赋给另一个算法(如sort())。例如,可在程序中石油类似于下面的代码段。

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>> make_int(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> n)
{
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">return</span> unique_ptr<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">new</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>(n));
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">void</span> show(unique_ptr<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>> &p1)
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">cout</span> << *a << <span class="hljs-string" style="color: rgb(136, 0, 0); box-sizing: border-box; outline: none !important;">' '</span>;
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> main()
{
    ...
    <span class="hljs-stl_container" style="box-sizing: border-box; outline: none !important;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">vector</span><unique_ptr<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>></span> > vp(size);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">for</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span> i = <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">0</span>; i < vp.size(); i++)
        vp[i] = make_int(rand() % <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">1000</span>);              <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// copy temporary unique_ptr</span>
    vp.push_back(make_int(rand() % <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">1000</span>));     <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// ok because arg is temporary</span>
    for_each(vp.begin(), vp.end(), show);           <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// use for_each()</span>
    ...
}</code>

其中push_back调用没有问题,因为它返回一个临时unique_ptr,该unique_ptr被赋给vp中的一个unique_ptr。另外,如果按值而不是按引用给show()传递对象,for_each()将非法,因为这将导致使用一个来自vp的非临时unique_ptr初始化pi,而这是不允许的。前面说过,编译器将发现错误使用unique_ptr的企图。 在unique_ptr为右值时,可将其赋给shared_ptr,这与将一个unique_ptr赋给一个需要满足的条件相同。与前面一样,在下面的代码中,make_int()的返回类型为unique_ptr<int>:

<code class="language-cpp hljs " style="display: block; padding: 0.5em; background-color: transparent !important; color: rgb(0, 0, 0); box-sizing: border-box; font-family: 'Source Code Pro', monospace; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; outline: none !important; background-position: initial initial; background-repeat: initial initial;">unique_ptr<<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>> pup(make_int(rand() % <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">1000</span>));   <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// ok</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>> spp(pup);                       <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// not allowed, pup as lvalue</span>
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box; font-weight: bold; outline: none !important;">shared_ptr</span><<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box; font-weight: bold; outline: none !important;">int</span>> spr(make_int(rand() % <span class="hljs-number" style="color: rgb(0, 136, 0); box-sizing: border-box; outline: none !important;">1000</span>));   <span class="hljs-comment" style="color: rgb(136, 136, 136); box-sizing: border-box; outline: none !important;">// ok</span></code>

模板shared_ptr包含一个显式构造函数,可用于将右值unique_ptr转换为shared_ptr。shared_ptr将接管原来归unique_ptr所有的对象。 在满足unique_ptr要求的条件时,也可使用auto_ptr,但unique_ptr是更好的选择。如果你的编译器没有unique_ptr,可考虑使用Boost库提供的scoped_ptr,它与unique_ptr类似。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python小屋

Python字符串处理小案例

连续5天30个小时的Python培训圆满结束,明天早上5点半出发赶飞机回烟台,晚上收拾行李的时候突然想起来20年前做过的一个C语言题目:假设有一个字符串,里面有...

30450
来自专栏java一日一条

Java面试参考指南(一)

Java是一种基于面向对象概念的编程语言,使用高度抽象化来解决现实世界的问题。 面向对象的方法将现实世界中的对象进行概念化,以便于在应用之间进行重用。例如...

19430
来自专栏Java学习网

Java中提高代码复用性的方法及规范总结

一个好的程序员一定是用最少的代码实现最多的功能,代码复用是程序员所追求和期望的,这也是Java语言所提倡的;根据以往开发经验整理了一些能够提高代码复用性方法和规...

45870
来自专栏java学习

Java每日一练(2017/8/16)

最新通知 ●回复"每日一练"获取以前的题目! ●【新】Android视频更新了!(回复【安卓视频】获取下载链接) ●【新】Ajax知识点视频更新了!(回复【学习...

30560
来自专栏calmound

UVA Machined Surfaces

题意:这道题我读了很久,也没有读懂最后看的解体报告才懂得题意,题目不难,但是还是错了两次,几个字符窜,左边的‘x’向右边移动当和右边的‘x’连接时候,求剩下的字...

36760
来自专栏take time, save time

你所能用到的数据结构之番外篇---逆袭的面向对象(一)

     对于番外篇,我深刻能明白在大多数人眼里就和电视剧的广告一样,说实话,我也不喜欢这种感觉,因为这样会让人觉得是在欺骗消费者啊~~~阿西巴~~~但是我实在...

34980
来自专栏HappenLee的技术杂谈

C++雾中风景番外篇:理解C++的复杂声明与声明解析

在编写C/C++代码时偶尔能看到如下的复杂声明:float(*(*e[10])(int*))[5]。我想你的第一反应一定是:MMP。虽然我们在实际工作之中是很少...

9520
来自专栏java学习

Java每日一练(2017/7/20)

最新通知 ●回复"每日一练"获取以前的题目! ●【新】Ajax知识点视频更新了!(回复【学习视频】获取下载链接) ●【新】HTML5知识点视频更新了!(回复【前...

26760
来自专栏HappenLee的技术杂谈

C++雾中风景9:emplace_back与可变长模板

emplace_back方法最大的改进就在与可以利用类本身的构造函数直接在内存之中构建对象,而不需要调用类的拷贝构造函数与移动构造函数。

9020
来自专栏机器之心

码如其人,同学你能写一手漂亮的Python函数吗

与多数现代编程语言一样,在 Python 中,函数是抽象和封装的基本方法之一。你在开发阶段或许已经写过数百个函数,但并非每个函数都生而平等。写出「糟糕的」函数会...

13620

扫码关注云+社区

领取腾讯云代金券