精华内容
下载资源
问答
  • master:Master数据库是SQLServer中最重要的系统数据库,记录了SQLServer系统级的信息.包括:系统中所有的登录账号及其密码,系统配置信息,所有数据库的信息,所有用户数据库的主文件地址等,还包括许多系统存储过程,用以...

    930ffc989e0a7d9217a1093809fc5811.png数据库:系统数据库(master、model、msdb、tempdb)、数据库快照、自定义数据库组成 三部分组成。

    master:Master数据库是SQL Server中最重要的系统数据库,记录了SQL Server系统级的信息.

    包括:系统中所有的登录账号及其密码,系统配置信息,所有数据库的信息,所有用户数据库的主文件地址等,还包括许多系统存储过程,用以执行某些系统操作.

    Master数据库是整个系统中最重要的数据库,如果丢失Master数据库,对于恢复所有用户数据库将非常困难.因此,保存Master数据库的最新备份是非常重要的的事情.

    tempdb 数据库

    tempdb 数据库保存所有的临时表和临时存储过程。它还满足任何其它的临时存储要求,例如存储 SQL Server 生成的工作表。tempdb 数据库是全局资源,所有连接到系统的用户的临时表和存储过程都存储在该数据库中。tempdb 数据库在 SQL Server 每次启动时都重新创建,因此该数据库在系统启动时总是干净的。临时表和存储过程在连接断开时自动除去,而且当系统关闭后将没有任何连接处于活动状态,因此 tempdb 数据库中没有任何内容会从 SQL Server 的一个会话保存到另一个会话。

    默认情况下,在 SQL Server 在运行时 tempdb 数据库会根据需要自动增长。不过,与其它数据库不同,每次启动数据库引擎时,它会重置为其初始大小。如果为 tempdb 数据库定义的大小较小,则每次重新启动 SQL Server时,将tempdb 数据库的大小自动增加到支持工作负荷所需的大小这一工作可能会成为系统处理负荷的一部分。为避免这种开销,可以使用 ALTER DATABASE 增加 tempdb 数据库的大小。

    model 数据库

    model 数据库用作在系统上创建的所有数据库的模板。当发出 CREATE DATABASE 语句时,新数据库的第一部分通过复制 model 数据库中的内容创建,剩余部分由空页填充。由于 SQL Server 每次启动时都要创建 tempdb 数据库,model 数据库必须一直存在于 SQL Server 系统中。

    msdb 数据库

    msdb 数据库供 SQL Server 代理程序调度警报和作业以及记录操作员时使用。

    展开全文
  •  前面的文章中,细致地分析了构造函数,拷贝构造函数,赋值运算符,析构函数这几个类中最重要函数的用法。  如果严格地遵循这些做法,可以消除绝大部分资源管理的问题。  然而,要想更灵活的使用对象中的资源...

    前言

      在前面的文章中,细致地分析了构造函数,拷贝构造函数,赋值运算符,析构函数这几个类中最重要函数的用法。

      如果严格地遵循这些做法,可以消除绝大部分资源管理的问题。

      然而,要想更灵活的使用对象中的资源,仅仅这些还不够。譬如,若你想自己控制对象资源的生命周期(不要在作用域结束的时候自动被析构掉),那就应当好好考虑下智能指针了。

      有人说,智能指针是属于设计模式范畴的产物,这么说有点偏激,但也确实有点道理。

    问题分析

      我们假定有一个投资类Investment:

    1 class Investment
    2 {
    3     // ......
    4 };

      很多其他的投资类型都由这个类派生出来,比如股票投资,基金投资等等。

      进一步假设,有某个工厂函数专门供应特定的Investment对象:

    1 Investment * createInvestment();

      必须说明的是,这个函数是通过new来在堆中创建对象的,因此,函数结束后,资源并不会释放掉,而是需要调用这个函数的用户来手工释放掉,如下所示:

    1 void f()
    2 {
    3     // ......
    4     Investment * pInv = createInvestment();
    5     // ......
    6     delete pInv;
    7     // ......
    8 }

      下面问题来了:如果在 4 - 6行之间有 continue 或者 goto 或者其他中断程序执行的语句,那么将会导致 delete 无法运行,从而内存泄露。

      这种情况下,用户肯定是想 pInv 在作用域结束的时候就会自动地释放掉,好在智能指针能解决这个问题。

    智能指针介绍

      智能指针的本质其实是一个能够帮用户管理资源的类指针对象。

      许多资源被动态分配于heap后被用于单一区块或函数内,智能指针可以让资源在离开控制流的时候得到释放。

      应用得比较多的有auto_ptr和shared_ptr两种智能指针。

      前者管理的资源必须是一个智能指针所指向的。当前者进行赋值的时候,会将赋值运算符右值的智能指针变成NULL,而其左值获得右边指针原来指向的资源。

      后者管理的资源则未必,它允许多个智能指针指向同一份资源,同时会统计资源被指的个数,只有指向该资源的智能指针都离开了作用域,才会正式析构掉资源。

      智能指针的使用:

    1 void f()
    2 {
    3     // ......
    4     std::auto_ptr<Investment>pInv(createInvestment());
    5     std::shared_ptr<Investment>pInv(createInvestment());
    6     // ......
    7 }

      在构造好了智能指针之后,便可以不用理会该资源回收的事,智能指针将会帮你打理!

      如果要通过智能指针获得原始资源指针,则调用智能指针的 .get() 即可,而如果要访问原始资源,智能指针重载了->和*()操作符,使用起来和原始指针一样。

      另外,智能指针shared_ptr还可以自定义删除器,指定删除对象时(指向资源的指针数为0)要做的具体事情(不一定是销毁资源)。

      由于智能指针的类型很多,使用方法也五花八门,这里就不一一介绍了,请参考相关的使用手册。

    小结

      1. 当你需要提前实现多态的话,请new一个子类并将结果返回给一个父类指针。

      2. 智能指针不支持内置类型,那是因为C++认为Vector可以完全取代动态分配而得到的数组。

    转载于:https://www.cnblogs.com/scut-fm/p/3972598.html

    展开全文
  • 用户可以通过该组件操作数据库,包括新建、修改、删除数据库、表、视图等数据库对象,新建查询、设置关系图、设置系统安全、数据库复制、数据备份、恢复等操作,是SSMS中最常用、也是最重要的一个组件。 (1)SSMS的...

    1.SQL Server Management Studio(SSMS)对象资源管理器的使用
    对象资源管理器(SSMS)是一种集成工具,可以查看和管理所有服务器类型的对象。用户可以通过该组件操作数据库,包括新建、修改、删除数据库、表、视图等数据库对象,新建查询、设置关系图、设置系统安全、数据库复制、数据备份、恢复等操作,是SSMS中最常用、也是最重要的一个组件。
    SSMS的使用
    在windows界面单击"开始"→"程序" →" MicroSoft SQL Server 2012"→"SQL Server Management Studio",启动对象资源管理器,观察SSMS界面。
    2.查询分析器的使用
    在SSMS窗口中单击"新建查询"按钮,在对象资源管理器右侧会出现“查询分析器”窗口,在窗口中输入下列命令:
    USE master
    SELECT * FROM dbo.spt_values
    GO
    在这里插入图片描述
    运行结果;
    在这里插入图片描述

    展开全文
  • 同时也有许多其它类型的资源文件句柄、重要的片断、Windows的GDI资源,等等。将资源的概念推广到程序创建、释放的所有对象也是十分方便的,无论对象分配的还是或者是全局作用于内生命的。  ...

    我最喜欢的对资源的定义是:"任何在你的程序中获得并在此后释放的东西?quot;内存是一个相当明显的资源的例子。它需要用new来获得,用delete来释放。同时也有许多其它类型的资源文件句柄、重要的片断、Windows中的GDI资源,等等。将资源的概念推广到程序中创建、释放的所有对象也是十分方便的,无论对象是在堆中分配的还是在栈中或者是在全局作用于内生命的。

      对于给定的资源的拥有着,是负责释放资源的一个对象或者是一段代码。所有权分立为两种级别——自动的和显式的(automatic and explicit),如果一个对象的释放是由语言本身的机制来保证的,这个对象的就是被自动地所有。例如,一个嵌入在其他对象中的对象,他的清除需要其他对象来在清除的时候保证。外面的对象被看作嵌入类的所有者。   类似地,每个在栈上创建的对象(作为自动变量)的释放(破坏)是在控制流离开了对象被定义的作用域的时候保证的。这种情况下,作用于被看作是对象的所有者。注意所有的自动所有权都是和语言的其他机制相容的,包括异常。无论是如何退出作用域的——正常流程控制退出、一个break语句、一个return、一个goto、或者是一个throw——自动资源都可以被清除。

      到目前为止,一切都很好!问题是在引入指针、句柄和抽象的时候产生的。如果通过一个指针访问一个对象的话,比如对象在堆中分配,C++不自动地关注它的释放。程序员必须明确的用适当的程序方法来释放这些资源。比如说,如果一个对象是通过调用new来创建的,它需要用delete来回收。一个文件是用CreateFile(Win32 API)打开的,它需要用CloseHandle来关闭。用EnterCritialSection进入的临界区(Critical Section)需要LeaveCriticalSection退出,等等。一个""指针,文件句柄,或者临界区状态没有所有者来确保它们的最终释放。基本的资源管理的前提就是确保每个资源都有他们的所有者。

    1.2.1 第一条规则(RAII

      一个指针,一个句柄,一个临界区状态只有在我们将它们封装入对象的时候才会拥有所有者。这就是我们的第一规则:在构造函数中分配资源,在析构函数中释放资源。

      当你按照规则将所有资源封装的时候,你可以保证你的程序中没有任何的资源泄露。这点在当封装对象(Encapsulating Object)在栈中建立或者嵌入在其他的对象中的时候非常明显。但是对那些动态申请的对象呢?不要急!任何动态申请的东西都被看作一种资源,并且要按照上面提到的方法进行封装。这一对象封装对象的链不得不在某个地方终止。它最终终止在最高级的所有者,自动的或者是静态的。这些分别是对离开作用域或者程序时释放资源的保证。

      下面是资源封装的一个经典例子。在一个多线程的应用程序中,线程之间共享对象的问题是通过用这样一个对象联系临界区来解决的。每一个需要访问共享资源的客户需要获得临界区。例如,这可能是Win32下临界区的实现方法。

    class CritSect

    {

     friend class Lock;

     public:

      CritSect () { InitializeCriticalSection (&_critSection); }

      ~CritSect () { DeleteCriticalSection (&_critSection); }

     private:

      void Acquire ()

      {

       EnterCriticalSection (&_critSection);

      }

      void Release ()

      {

       LeaveCriticalSection (&_critSection);

      }

     private:

      CRITICAL_SECTION _critSection;

    };

      这里聪明的部分是我们确保每一个进入临界区的客户最后都可以离开。"进入"临界区的状态是一种资源,并应当被封装。封装器通常被称作一个锁(lock)。

    class Lock

    {

     public:

      Lock (CritSect& critSect) : _critSect (critSect)

      {

       _critSect.Acquire ();

      }

      ~Lock ()

      {

       _critSect.Release ();

      }

     private

      CritSect & _critSect;

    };

      锁一般的用法如下:

    void Shared::Act () throw (char *)

    {

     Lock lock (_critSect);

     // perform action —— may throw

     // automatic destructor of lock

    }

      注意无论发生什么,临界区都会借助于语言的机制保证释放。

      还有一件需要记住的事情——每一种资源都需要被分别封装。这是因为资源分配是一个非常容易出错的操作,是要资源是有限提供的。我们会假设一个失败的资源分配会导致一个异常——事实上,这会经常的发生。所以如果你想试图用一个石头打两只鸟的话,或者在一个构造函数中申请两种形式的资源,你可能就会陷入麻烦。只要想想在一种资源分配成功但另一种失败抛出异常时会发生什么。因为构造函数还没有全部完成,析构函数不可能被调用,第一种资源就会发生泄露。

    这种情况可以非常简单的避免。无论何时你有一个需要两种以上资源的类时,写两个小的封装器将它们嵌入你的类中。每一个嵌入的构造都可以保证删除,即使包装类没有构造完成。

    1.2.2 Smart Pointers

      我们至今还没有讨论最常见类型的资源——用操作符new分配,此后用指针访问的一个对象。我们需要为每个对象分别定义一个封装类吗?(事实上,C++标准模板库已经有了一个模板类,叫做auto_ptr,其作用就是提供这种封装。我们一会儿在回到auto_ptr。)让我们从一个极其简单、呆板但安全的东西开始。看下面的Smart Pointer模板类,它十分坚固,甚至无法实现。

    template <class T>

    class SmartPointer

    {

     public:

      ~SmartPointer () { delete _p; }

      T * operator->() { return _p; }

      T const * operator->() const { return _p; }

     protected:

      SmartPointer (): _p (0) {}

      explicit SmartPointer (T* p): _p (p) {}

      T * _p;

    };

      为什么要把SmartPointer的构造函数设计为protected呢?如果我需要遵守第一条规则,那么我就必须这样做。资源——在这里是class T的一个对象——必须在封装器的构造函数中分配。但是我不能只简单的调用new T,因为我不知道T的构造函数的参数。因为,在原则上,每一个T都有一个不同的构造函数;我需要为他定义个另外一个封装器。模板的用处会很大,为每一个新的类,我可以通过继承SmartPointer定义一个新的封装器,并且提供一个特定的构造函数。

    class SmartItem: public SmartPointer<Item>

    {

     public:

      explicit SmartItem (int i)

      : SmartPointer<Item> (new Item (i)) {}

    };

      为每一个类提供一个Smart Pointer真的值得吗?说实话——不!他很有教学的价值,但是一旦你学会如何遵循第一规则的话,你就可以放松规则并使用一些高级的技术。这一技术是让SmartPointer的构造函数成为public,但是只是是用它来做资源转换(Resource Transfer)我的意思是用new操作符的结果直接作为SmartPointer的构造函数的参数,像这样:

    SmartPointer<Item> item (new Item (i));

      这个方法明显更需要自控性,不只是你,而且包括你的程序小组的每个成员。他们都必须发誓出了作资源转换外不把构造函数用在人以其他用途。幸运的是,这条规矩很容易得以加强。只需要在源文件中查找所有的new即可。

    1.2.3 Resource Transfer

      到目前为止,我们所讨论的一直是生命周期在一个单独的作用域内的资源。现在我们要解决一个困难的问题——如何在不同的作用域间安全的传递资源。这一问题在当你处理容器的时候会变得十分明显。你可以动态的创建一串对象,将它们存放至一个容器中,然后将它们取出,并且在最终安排它们。为了能够让这安全的工作——没有泄露——对象需要改变其所有者。

      这个问题的一个非常显而易见的解决方法是使用Smart Pointer,无论是在加入容器前还是还找到它们以后。这是他如何运作的,你加入Release方法到Smart Pointer中:

    template <class T>

    T * SmartPointer<T>::Release ()

    {

    T * pTmp = _p;

    _p = 0;

    return pTmp;

    }

      注意在Release调用以后,Smart Pointer就不再是对象的所有者了——它内部的指针指向空。现在,调用了Release都必须是一个负责的人并且迅速隐藏返回的指针到新的所有者对象中。在我们的例子中,容器调用了Release,比如这个Stack的例子:

    void Stack::Push (SmartPointer <Item> & item) throw (char *)

    {

    if (_top == maxStack)

    throw "Stack overflow";

    _arr [_top++] = item.Release ();

    };

      同样的,你也可以再你的代码中用加强Release的可靠性。

    相应的Pop方法要做些什么呢?他应该释放了资源并祈祷调用它的是一个负责的人而且立即作一个资源传递它到一个Smart Pointer?这听起来并不好。

    1.2.4 Strong Pointers

      资源管理在内容索引(Windows NT Server上的一部分,现在是Windows 2000)上工作,并且,我对这十分满意。然后我开始想……这一方法是在这样一个完整的系统中形成的,如果可以把它内建入语言的本身岂不是一件非常好?我提出了强指针(Strong Pointer)和弱指针(Weak Pointer)。一个Strong Pointer会在许多地方和我们这个SmartPointer相似--它在超出它的作用域后会清除他所指向的对象。资源传递会以强指针赋值的形式进行。也可以有Weak Pointer存在,它们用来访问对象而不需要所有对象--比如可赋值的引用。

      任何指针都必须声明为Strong或者Weak,并且语言应该来关注类型转换的规定。例如,你不可以将Weak Pointer传递到一个需要Strong Pointer的地方,但是相反却可以。Push方法可以接受一个Strong Pointer并且将它转移到Stack中的Strong Pointer的序列中。Pop方法将会返回一个Strong Pointer。把Strong Pointer的引入语言将会使垃圾回收成为历史。

      这里还有一个小问题--修改C++标准几乎和竞选美国总统一样容易。当我将我的注意告诉给Bjarne Stroutrup的时候,他看我的眼神好像是我刚刚要向他借一千美元一样。

    然后我突然想到一个念头。我可以自己实现Strong Pointers。毕竟,它们都很想Smart Pointers。给它们一个拷贝构造函数并重载赋值操作符并不是一个大问题。事实上,这正是标准库中的auto_ptr有的。重要的是对这些操作给出一个资源转移的语法,但是这也不是很难。

    template <class T>

    SmartPointer<T>::SmartPointer (SmartPointer<T> & ptr)

    {

    _p = ptr.Release ();

    }

    template <class T>

    void SmartPointer<T>::operator = (SmartPointer<T> & ptr)

    {

    if (_p != ptr._p)

    {

    delete _p;

    _p = ptr.Release ();

    }

    }

      使这整个想法迅速成功的原因之一是我可以以值方式传递这种封装指针!我有了我的蛋糕,并且也可以吃了。看这个Stack的新的实现:

    class Stack

    {

    enum { maxStack = 3 };

    public:

    Stack ()

    : _top (0)

    {}

    void Push (SmartPointer<Item> & item) throw (char *)

    {

    if (_top >= maxStack)

    throw "Stack overflow";

    _arr [_top++] = item;

    }

    SmartPointer<Item> Pop ()

    {

    if (_top == 0)

    return SmartPointer<Item> ();

    return _arr [--_top];

    }

    private

    int _top;

    SmartPointer<Item> _arr [maxStack];

    };

      Pop方法强制客户将其返回值赋给一个Strong Pointer,SmartPointer<Item>。任何试图将他对一个普通指针的赋值都会产生一个编译期错误,因为类型不匹配。此外,因为Pop以值方式返回一个Strong Pointer(Pop的声明时SmartPointer<Item>后面没有&符号),编译器在return时自动进行了一个资源转换。他调用了operator =来从数组中提取一个Item,拷贝构造函数将他传递给调用者。调用者最后拥有了指向Pop赋值的Strong Pointer指向的一个Item

    我马上意识到我已经在某些东西之上了。我开始用了新的方法重写原来的代码。

    1.2.5 Parser

    我过去有一个老的算术操作分析器,是用老的资源管理的技术写的。分析器的作用是在分析树中生成节点,节点是动态分配的。例如分析器的Expression方法生成一个表达式节点。我没有时间用Strong Pointer去重写这个分析器。我令ExpressionTermFactor方法以传值的方式将Strong Pointer返回到Node中。看下面的Expression方法的实现:

    SmartPointer<Node> Parser::Expression()

    {

    // Parse a term

    SmartPointer<Node> pNode = Term ();

    EToken token = _scanner.Token();

    if ( token == tPlus || token == tMinus )

    {

    // Expr := Term { ('+' | '-') Term }

    SmartPointer<MultiNode> pMultiNode = new SumNode (pNode);

    do

    {

    _scanner.Accept();

    SmartPointer<Node> pRight = Term ();

    pMultiNode->AddChild (pRight, (token == tPlus));

    token = _scanner.Token();

    } while (token == tPlus || token == tMinus);

    pNode = up_cast<Node, MultiNode> (pMultiNode);

    }

    // otherwise Expr := Term

    return pNode; // by value!

    }

      最开始,Term方法被调用。他传值返回一个指向NodeStrong Pointer并且立刻把它保存到我们自己的Strong Pointer,pNode中。如果下一个符号不是加号或者减号,我们就简单的把这个SmartPointer以值返回,这样就释放了Node的所有权。另外一方面,如果下一个符号是加号或者减号,我们创建一个新的SumMode并且立刻(直接传递)将它储存到MultiNode的一个Strong Pointer中。这里,SumNode是从MultiMode中继承而来的,而MulitNode是从Node继承而来的。原来的Node的所有权转给了SumNode

      只要是他们在被加号和减号分开的时候,我们就不断的创建terms,我们将这些term转移到我们的MultiNode中,同时MultiNode得到了所有权。最后,我们将指向MultiNodeStrong Pointer向上映射为指向ModeStrong Pointer,并且将他返回调用着。

      我们需要对Strong Pointers进行显式的向上映射,即使指针是被隐式的封装。例如,一个MultiNode是一个Node,但是相同的is-a关系在SmartPointer<MultiNode>SmartPointer<Node>之间并不存在,因为它们是分离的类(模板实例)并不存在继承关系。up-cast模板是像下面这样定义的:

    template<class To, class From>

    inline SmartPointer<To> up_cast (SmartPointer<From> & from)

    {

    return SmartPointer<To> (from.Release ());

    }

      如果你的编译器支持新加入标准的成员模板(member template)的话,你可以为SmartPointer<T>定义一个新的构造函数用来从接受一个class U

    template <class T>

    template <class U> SmartPointer<T>::SmartPointer (SPrt<U> & uptr)

    : _p (uptr.Release ())

    {}

      这里的这个花招是模板在U不是T的子类的时候就不会编译成功(换句话说,只在U is-a T的时候才会编译)。这是因为uptr的缘故。Release()方法返回一个指向U的指针,并被赋值为_p,一个指向T的指针。所以如果U不是一个T的话,赋值会导致一个编译时刻错误。

    std::auto_ptr

    后来我意识到在STL中的auto_ptr模板,就是我的Strong Pointer。在那时候还有许多的实现差异(auto_ptrRelease方法并不将内部的指针清零--你的编译器的库很可能用的就是这种陈旧的实现),但是最后在标准被广泛接受之前都被解决了。

    1.2.6 Transfer Semantics

      目前为止,我们一直在讨论在C++程序中资源管理的方法。宗旨是将资源封装到一些轻量级的类中,并由类负责它们的释放。特别的是,所有用new操作符分配的资源都会被储存并传递进Strong Pointer(标准库中的auto_ptr)的内部。

      这里的关键词是传递(passing)。一个容器可以通过传值返回一个Strong Pointer来安全的释放资源。容器的客户只能够通过提供一个相应的Strong Pointer来保存这个资源。任何一个将结果赋给一个""指针的做法都立即会被编译器发现。

    auto_ptr<Item> item = stack.Pop (); // ok

    Item * p = stack.Pop (); // Error! Type mismatch.

      以传值方式被传递的对象有value semantics 或者称为 copy semanticsStrong Pointers是以值方式传递的--但是我们能说它们有copy semantics吗?不是这样的!它们所指向的对象肯定没有被拷贝过。事实上,传递过后,源auto_ptr不在访问原有的对象,并且目标auto_ptr成为了对象的唯一拥有者(但是往往auto_ptr的旧的实现即使在释放后仍然保持着对对象的所有权)。自然而然的我们可以将这种新的行为称作Transfer Semantics

      拷贝构造函数(copy construcor)和赋值操作符定义了auto_ptrTransfer Semantics,它们用了非constauto_ptr引用作为它们的参数。

    auto_ptr (auto_ptr<T> & ptr);

    auto_ptr & operator = (auto_ptr<T> & ptr);

      这是因为它们确实改变了他们的源--剥夺了对资源的所有权。

    通过定义相应的拷贝构造函数和重载赋值操作符,你可以将Transfer Semantics加入到许多对象中。例如,许多Windows中的资源,比如动态建立的菜单或者位图,可以用有Transfer Semantics的类来封装。

    1.2.7 Strong Vectors

      标准库只在auto_ptr中支持资源管理。甚至连最简单的容器也不支持ownership semantics。你可能想将auto_ptr和标准容器组合到一起可能会管用,但是并不是这样的。例如,你可能会这样做,但是会发现你不能够用标准的方法来进行索引。

    vector< auto_ptr<Item> > autoVector;

      这种建造不会编译成功;

    Item * item = autoVector [0];

      另一方面,这会导致一个从autoVectauto_ptr的所有权转换:

    auto_ptr<Item> item = autoVector [0];

      我们没有选择,只能够构造我们自己的Strong Vector。最小的接口应该如下:

    template <class T>

    class auto_vector

    {

    public:

    explicit auto_vector (size_t capacity = 0);

    T const * operator [] (size_t i) const;

    T * operator [] (size_t i);

    void assign (size_t i, auto_ptr<T> & p);

    void assign_direct (size_t i, T * p);

    void push_back (auto_ptr<T> & p);

    auto_ptr<T> pop_back ();

    };

      你也许会发现一个非常防御性的设计态度。我决定不提供一个对vector的左值索引的访问,取而代之,如果你想设定(set)一个值的话,你必须用assign或者assign_direct方法。我的观点是,资源管理不应该被忽视,同时,也不应该在所有的地方滥用。在我的经验里,一个strong vector经常被许多push_back方法充斥着。

      Strong vector最好用一个动态的Strong Pointers的数组来实现:

    template <class T>

    class auto_vector

    {

    private

    void grow (size_t reqCapacity);

    auto_ptr<T> *_arr;

    size_t _capacity;

    size_t _end;

    };

      grow方法申请了一个很大的auto_ptr<T>的数组,将所有的东西从老的书组类转移出来,在其中交换,并且删除原来的数组。

      auto_vector的其他实现都是十分直接的,因为所有资源管理的复杂度都在auto_ptr中。例如,assign方法简单的利用了重载的赋值操作符来删除原有的对象并转移资源到新的对象:

    void assign (size_t i, auto_ptr<T> & p)

    {

    _arr [i] = p;

    }

      我已经讨论了push_backpop_back方法。push_back方法传值返回一个auto_ptr,因为它将所有权从auto_vector转换到auto_ptr中。

      对auto_vector的索引访问是借助auto_ptrget方法来实现的,get简单的返回一个内部指针。

    T * operator [] (size_t i)

    {

    return _arr [i].get ();

    }

      没有容器可以没有iterator。我们需要一个iteratorauto_vector看起来更像一个普通的指针向量。特别是,当我们废弃iterator的时候,我们需要的是一个指针而不是auto_ptr。我们不希望一个auto_vectoriterator在无意中进行资源转换。

    template<class T>

    class auto_iterator: public

    iterator<random_access_iterator_tag, T *>

    {

    public:

    auto_iterator () : _pp (0) {}

    auto_iterator (auto_ptr<T> * pp) : _pp (pp) {}

    bool operator != (auto_iterator<T> const & it) const

    { return it._pp != _pp; }

    auto_iterator const & operator++ (int) { return _pp++; }

    auto_iterator operator++ () { return ++_pp; }

    T * operator * () { return _pp->get (); }

    private

    auto_ptr<T> * _pp;

    };

    我们给auto_vect提供了标准的beginend方法来找回iterator

    class auto_vector

    {

    public:

    typedef auto_iterator<T> iterator;

    iterator begin () { return _arr; }

    iterator end () { return _arr + _end; }

    }; 

      你也许会问我们是否要利用资源管理重新实现每一个标准的容器?幸运的是,不;事实是strong vector解决了大部分所有权的需求。当你把你的对象都安全的放置到一个strong vector中,你可以用所有其它的容器来重新安排(weakpointer

    设想,例如,你需要对一些动态分配的对象排序的时候。你将它们的指针保存到一个strong vector中。然后你用一个标准的vector来保存从strong vector中获得的weak指针。你可以用标准的算法对这个vector进行排序。这种中介vector叫做permutation vector。相似的,你也可以用标准的maps, priority queues, heaps, hash tables等等。

    1.2.8 Code Inspection

      如果你严格遵照资源管理的条款,你就不会再资源泄露或者两次删除的地方遇到麻烦。你也降低了访问野指针的几率。同样的,遵循原有的规则,用delete删除用new申请的德指针,不要两次删除一个指针。你也不会遇到麻烦。但是,那个是更好的注意呢?

      这两个方法有一个很大的不同点。就是和寻找传统方法的bug相比,找到违反资源管理的规定要容易的多。后者仅需要一个代码检测或者一个运行测试,而前者则在代码中隐藏得很深,并需要很深的检查。

      设想你要做一段传统的代码的内存泄露检查。第一件事,你要做的就是grep所有在代码中出现的new,你需要找出被分配空间地指针都作了什么。你需要确定导致删除这个指针的所有的执行路径。你需要检查break语句,过程返回,异常。原有的指针可能赋给另一个指针,你对这个指针也要做相同的事。

      相比之下,对于一段用资源管理技术实现的代码。你也用grep检查所有的new,但是这次你只需要检查邻近的调用:

      ● 这是一个直接的Strong Pointer转换,还是我们在一个构造函数的函数体中?

      ● 调用的返回知是否立即保存到对象中,构造函数中是否有可以产生异常的代码。?

      ● 如果这样的话析构函数中时候有delete?

      下一步,你需要用grep查找所有的release方法,并实施相同的检查。

      不同点是需要检查、理解单个执行路径和只需要做一些本地的检验。这难道不是提醒你非结构化的和结构化的程序设计的不同吗?原理上,你可以认为你可以应付goto,并且跟踪所有的可能分支。另一方面,你可以将你的怀疑本地化为一段代码。本地化在两种情况下都是关键所在。

      在资源管理中的错误模式也比较容易调试。最常见的bug是试图访问一个释放过的strong pointer。这将导致一个错误,并且很容易跟踪。

    1.2.9 共享的所有权

      为每一个程序中的资源都找出或者指定一个所有者是一件很容易的事情吗?答案是出乎意料的,是!如果你发现了一些问题,这可能说明你的设计上存在问题。还有另一种情况就是共享所有权是最好的甚至是唯一的选择。

      共享的责任分配给被共享的对象和它的客户(client)。一个共享资源必须为它的所有者保持一个引用计数。另一方面,所有者再释放资源的时候必须通报共享对象。最后一个释放资源的需要在最后负责free的工作。

      最简单的共享的实现是共享对象继承引用计数的类RefCounted

    class RefCounted

    {

    public:

    RefCounted () : _count (1) {}

    int GetRefCount () const { return _count; }

    void IncRefCount () { _count++; }

    int DecRefCount () { return --_count; }

    private

    int _count;

    };

      按照资源管理,一个引用计数是一种资源。如果你遵守它,你需要释放它。当你意识到这一事实的时候,剩下的就变得简单了。简单的遵循规则--再构造函数中获得引用计数,在析构函数中释放。甚至有一个RefCountedsmart pointer等价物:

    template <class T>

    class RefPtr

    {

    public:

    RefPtr (T * p) : _p (p) {}

    RefPtr (RefPtr<T> & p)

    {

    _p = p._p;

    _p->IncRefCount ();

    }

    ~RefPtr ()

    {

    if (_p->DecRefCount () == 0)

    delete _p;

    }

    private

    T * _p;

    };

      注意模板中的T不比成为RefCounted的后代,但是它必须有IncRefCountDecRefCount的方法。当然,一个便于使用的RefPtr需要有一个重载的指针访问操作符。在RefPtr中加入转换语义学(transfer semantics)是读者的工作。

    1.2.10 所有权网络

      链表是资源管理分析中的一个很有意思的例子。如果你选择表成为链(link)的所有者的话,你会陷入实现递归的所有权。每一个link都是它的继承者的所有者,并且,相应的,余下的链表的所有者。下面是用smart pointer实现的一个表单元:

    class Link

    {

    // ...

    private

    auto_ptr<Link> _next;

    };

      最好的方法是,将连接控制封装到一个弄构进行资源转换的类中。

      对于双链表呢?安全的做法是指明一个方向,如forward:

    class DoubleLink

    {

    // ...

    private

    DoubleLink *_prev;

    auto_ptr<DoubleLink> _next;

    };

      注意不要创建环形链表。

      这给我们带来了另外一个有趣的问题--资源管理可以处理环形的所有权吗?它可以,用一个mark-and-sweep的算法。这里是实现这种方法的一个例子:

    template<class T>

    class CyclPtr

    {

    public:

    CyclPtr (T * p)

    :_p (p), _isBeingDeleted (false)

    {}

    ~CyclPtr ()

    {

    _isBeingDeleted = true;

    if (!_p->IsBeingDeleted ())

    delete _p;

    }

    void Set (T * p)

    {

    _p = p;

    }

    bool IsBeingDeleted () const { return _isBeingDeleted; }

    private

    T * _p;

    bool _isBeingDeleted;

    };

      注意我们需要用class T来实现方法IsBeingDeleted,就像从CyclPtr继承。对特殊的所有权网络普通化是十分直接的。

      将原有代码转换为资源管理代码

    如果你是一个经验丰富的程序员,你一定会知道找资源的bug是一件浪费时间的痛苦的经历。我不必说服你和你的团队花费一点时间来熟悉资源管理是十分值得的。你可以立即开始用这个方法,无论你是在开始一个新项目或者是在一个项目的中期。转换不必立即全部完成。下面是步骤。

    (1)       首先,在你的工程中建立基本的Strong Pointer。然后通过查找代码中的new来开始封装裸指针。

    (2)       最先封装的是在过程中定义的临时指针。简单的将它们替换为auto_ptr并且删除相应的delete。如果一个指针在过程中没有被删除而是被返回,用auto_ptr替换并在返回前调用release方法。在你做第二次传递的时候,你需要处理对release的调用。注意,即使是在这点,你的代码也可能更加"精力充沛"--你会移出代码中潜在的资源泄漏问题。

    (3)       下面是指向资源的裸指针。确保它们被独立的封装到auto_ptr中,或者在构造函数中分配在析构函数中释放。如果你有传递所有权的行为的话,需要调用release方法。如果你有容器所有对象,用Strong Pointers重新实现它们。

    (4)       接下来,找到所有对release的方法调用并且尽力清除所有,如果一个release调用返回一个指针,将它修改传值返回一个auto_ptr

    (5)       重复着一过程,直到最后所有newrelease的调用都在构造函数或者资源转换的时候发生。这样,你在你的代码中处理了资源泄漏的问题。对其他资源进行相似的操作。

    (6)       你会发现资源管理清除了许多错误和异常处理带来的复杂性。不仅仅你的代码会变得精力充沛,它也会变得简单并容易维护。

    展开全文
  • 现代市场经济中,薪酬管理是企业人力资源管理中最主要、最敏感环节之一,直接影响企业竞争力[1].一个好薪酬管理体系能够改善经营绩效、控制企业成本、留住企业人才、保持企业稳定发展。因此,如何建立与企业...
  • c++的设计,对于资源管理是非常重要的,一旦管理不好就会容易导致内存泄漏,从而出现严重的问题,c++之父引入了资源管理的手法,名叫RAII,它是“Resource Acquisition Is Initialization”的首字母缩写。...
  • 同时也有许多其它类型的资源文件句柄、重要的片断、Windows的GDI资源,等等。将资源的概念推广到程序创建、释放的所有对象也是十分方便的,无论对象分配的还是或者是全局作用于内生命的。 我...
  • 同时也有许多其它类型的资源文件句柄、重要的片断、Windows的GDI资源,等等。将资源的概念推广到程序创建、释放的所有对象也是十分方便的,无论对象分配的还是或者是全局作用于内生命的。
  • 我们知道, Kubernetes 里面, Pod 是最小的原子调度单位,这就意味着,所有和调度和资源管理有关的属性,应该都是属于 Pod 对象的字段,而这些字段,最重要的部分就是 Pod 的 CPU 和内存配置. Kubernetes ,...
  • 同时也有许多其它类型的资源文件句柄、重要的片断、Windows的GDI资源等等。很容易的可以将资源的概念推广到程序创建、释放的所有对象,无论对象分配的还是或者是全局作用域内声明的。 对于给定...
  • 配置此数据源时候最重要就是选择业务对象,但是那个业务对象列表总是出问题。搞得我很不爽。老是是旧数据,修改后没有及时更新。后来网上搜了下,解决办法:将vs IDE ctrl+W ,L 服务器资源管理中的数据连接...
  • Android应用里,耗费内存就是图片资源。而且Android系统,读取位图Bitmap时,分给虚拟机中的图片堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常。所以,对于图片内存优化,是Android应用开发...
  • 4. 新增客户时,重要的客户资料不允许为空,避免销售人员抢占客户; 5. 重要客户要填写备忘录,销售人员可随时查看; 6. 销售人员可非常方便的查看自己的工作清单,可查看任一时段自己的工作清单; 7. 自动提醒 ...
  • 因此,制订物料需求计划前就必须具备以下的基本数据:第一项数据是主生产计划,它指明某一计划时间段内应生产出的各种产品和备件,它是物料需求计划制订的一个最重要的数据来源。第二项数据是物料清单(BOM),它...
  • 最重要的一点,细心的朋友应该看到了加载AssetBundle的MrcAssetManager类,我们使用的WWW加载对象可以使用WWW.LoadFromCacheOrDownload方法,其中第一个参数是资源的url,第二个参数则是我们的要加载的版本号...
  • 嵌套 DataRelation:讨论嵌套 DataRelation 对象在以 XML 数据形式表示 DataSet 内容时的重要性,并描述如何创建这些对象。 从 XML 架构 (XSD) 生成 DataSet 关系结构:描述从 XML 架构定义语言 (XSD) 架构创建 ...
  • 因此,薪酬体系改革众多的企业改革之是最为重要的改革之一,同时也是不易推行的、风险最大的改革。 由于牵动着企业上下每个员工的切身利益,贸然全盘推翻以往的分配制度,效果有可能会适得其反,轻则影响员工...
  • 首先是界面设计,最重要的就是简洁美观而且要符合普通用户的使用习惯。各个组件的功能也要设计得让用户有一种”望文生义”的效果。 其次,便是结构设计。为了增强各个模块的独立性,将各个功能都分开写成独立的方法...
  • 最重要的信息,并帮助读者消化最难以理解的概念。本书是一本友好而易于使用的自学指南,适合用做编 程课程的教材,也可供熟悉其他语言的开发人员参考,以更深入地理解C++语言的基本知识。 本书采用了各种教学技巧...
  • 最重要的信息,并帮助读者消化最难以理解的概念。本书是一本友好而易于使用的自学指南,适合用做编 程课程的教材,也可供熟悉其他语言的开发人员参考,以更深入地理解C++语言的基本知识。 本书采用了各种教学技巧...
  • 最重要的信息,并帮助读者消化最难以理解的概念。本书是一本友好而易于使用的自学指南,适合用做编 程课程的教材,也可供熟悉其他语言的开发人员参考,以更深入地理解C++语言的基本知识。 本书采用了各种教学技巧...
  • 最重要的信息,并帮助读者消化最难以理解的概念。本书是一本友好而易于使用的自学指南,适合用做编 程课程的教材,也可供熟悉其他语言的开发人员参考,以更深入地理解C++语言的基本知识。 本书采用了各种教学技巧...
  • 作为物流企业的管理者,早已充份认识到管理在企业整个企业运作过程中的重要性,通过计算机管理系统对企业进行管理,解决传统管理方法运作节奏和企业内部资源不能及时作出匹配和调整问题,进而对企业内物流设施...
  • Linux 内核文件 Cache 管理机制介绍

    千次阅读 2017-04-14 14:57:41
    操作系统是计算机上最重要的系统软件,它负责管理各种物理资源,并向应用程序提供各种抽象接口以便其使用这些物理资源。从应用程序的角度看,操作系统提供了一个统一的虚拟机,该虚拟机没有各种机器的具体细节,...
  • 云计算正在发展为共享资源的关键计算范例。... 最重要的是,描述了一种基于可满足性的技术,该技术可自动分析被管理对象的状态并计划用于维护该对象的所需操作。 提供了案例研究的结果,以验证此方法的可行性。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 450
精华内容 180
关键字:

在管理对象中最重要的资源是