dlib C++ Library - smart_pointers.cpp

    // Copyright (C) 2007  Davis E. King (davisking@users.sourceforge.net)
    // License: Boost Software License   See LICENSE.txt for the full license.

    #include <dlib/smart_pointers.h>
    #include <sstream>
    #include <string>
    #include <cstdlib>
    #include <ctime>

    #include "tester.h"

    namespace
    {

        using namespace test;
        using namespace dlib;
        using namespace std;

        logger dlog("test.smart_pointers");

        int counter = 0;
        struct base
        {
            int num;
            virtual ~base() {}
        };

        struct derived : public base
        {
            derived() {  ++counter; }
            ~derived() { --counter; }
        };

        int deleter_called = 0;
        void deleter ( derived* p) { ++deleter_called; delete p; }
        void deleter_base ( base* p) { ++deleter_called; delete p; }
        typedef void (*D)(derived*);
        typedef void (*Db)(base*);

        void smart_pointers_test (
        )
        /*!
            ensures
                - runs tests on the smart pointers for compliance with the specs
        !*/
        {
            counter = 0;
            deleter_called = 0;

            {
                DLIB_CASSERT(counter == 0,counter);
                scoped_ptr<base> p1(new derived);
                scoped_ptr<derived> p2(new derived);
                scoped_ptr<derived> p3;
                DLIB_CASSERT(counter == 2,counter);
                DLIB_CASSERT(!p3,"");

                p1->num = 1;
                p2->num = 2;
                DLIB_CASSERT(p1->num == 1,"");
                DLIB_CASSERT(p2->num == 2,"");

                (*p1).num = 3;
                (*p2).num = 4;
                DLIB_CASSERT(p1->num == 3,"");
                DLIB_CASSERT(p2->num == 4,"");

                DLIB_CASSERT(counter == 2,counter);

                DLIB_CASSERT(p1,"");
                DLIB_CASSERT(p2,"");

                DLIB_CASSERT(counter == 2,counter);
                p1.reset();
                DLIB_CASSERT(counter == 1,counter);
                DLIB_CASSERT(!p1,"");
                DLIB_CASSERT(p2,"");
                p1.reset(new derived);
                DLIB_CASSERT(counter == 2,counter);
                DLIB_CASSERT(p1,"");

                DLIB_CASSERT(counter == 2,counter);
                p2.reset();
                DLIB_CASSERT(counter == 1,counter);
                DLIB_CASSERT(!p2,"");
                derived* d = new derived;
                p2.reset(d);
                DLIB_CASSERT(p2.get() == d,"");
                DLIB_CASSERT(counter == 2,counter);
                DLIB_CASSERT(p2,"");
                DLIB_CASSERT(!p3,"");
                p2->num = 9;
                swap(p2,p3);
                DLIB_CASSERT(!p2,"");
                DLIB_CASSERT(p3,"");
                DLIB_CASSERT(p3->num == 9,"");
                p2.swap(p3);
                DLIB_CASSERT(p2,"");
                DLIB_CASSERT(!p3,"");
                DLIB_CASSERT(p2->num == 9,"");

                DLIB_CASSERT(counter == 2,counter);

            }
            DLIB_CASSERT(counter == 0,counter);

            {
                base* realp1 = new derived;
                derived* realp2 = new derived;
                shared_ptr<base> p1(realp1);
                shared_ptr<derived> p2(realp2,&deleter);
                shared_ptr<base> p3;
                shared_ptr<derived> p4;
                DLIB_CASSERT(p4.get() == 0,"");
                DLIB_CASSERT(p1,"");
                DLIB_CASSERT(p2,"");
                DLIB_CASSERT(!p3,"");
                DLIB_CASSERT(!p4,"");
                DLIB_CASSERT(p1.get() == realp1,"");
                DLIB_CASSERT(p2.get() == realp2,"");
                p1->num = 1;
                p2->num = 2;
                DLIB_CASSERT((*p1).num == 1,"");
                DLIB_CASSERT((*p2).num == 2,"");

                p1.swap(p3);
                DLIB_CASSERT(!p1,"");
                DLIB_CASSERT(p3,"");
                DLIB_CASSERT((*p3).num == 1,"");
                DLIB_CASSERT(p3->num == 1,"");
                swap(p1,p3);
                DLIB_CASSERT(p1,"");
                DLIB_CASSERT(!p3,"");
                DLIB_CASSERT((*p1).num == 1,"");
                DLIB_CASSERT(p1->num == 1,"");
                DLIB_CASSERT(counter == 2,counter);

                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(p2.unique(),"");
                DLIB_CASSERT(!p3.unique(),"");
                DLIB_CASSERT(!p4.unique(),"");

                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(p2.use_count() == 1,"");
                DLIB_CASSERT(p3.use_count() == 0,"");
                DLIB_CASSERT(p4.use_count() == 0,"");

                shared_ptr<base> p11(p1);

                DLIB_CASSERT(!p1.unique(),"");
                DLIB_CASSERT(p2.unique(),"");
                DLIB_CASSERT(!p3.unique(),"");
                DLIB_CASSERT(!p4.unique(),"");

                DLIB_CASSERT(p1.use_count() == 2,"");
                DLIB_CASSERT(p2.use_count() == 1,"");
                DLIB_CASSERT(p3.use_count() == 0,"");
                DLIB_CASSERT(p4.use_count() == 0,"");

                shared_ptr<base> p22(p2);

                DLIB_CASSERT(!p1.unique(),"");
                DLIB_CASSERT(!p2.unique(),"");
                DLIB_CASSERT(!p3.unique(),"");
                DLIB_CASSERT(!p4.unique(),"");

                DLIB_CASSERT(p1.use_count() == 2,"");
                DLIB_CASSERT(p2.use_count() == 2,"");
                DLIB_CASSERT(p3.use_count() == 0,"");
                DLIB_CASSERT(p4.use_count() == 0,"");

                DLIB_CASSERT(p11.get() == realp1,"");
                DLIB_CASSERT(p11 == p1,"");
                DLIB_CASSERT(p22 == p2,"");
                DLIB_CASSERT(p3 == p4,"");
                DLIB_CASSERT(p11 != p22,"");
                DLIB_CASSERT(p1 != p2,"");
                DLIB_CASSERT(p3 != p1,"");
                DLIB_CASSERT(p3 != p11,"");
                DLIB_CASSERT(p3 != p2,"");

                p1 = p1 = p1;
                DLIB_CASSERT(p1.use_count() == 2,"");
                DLIB_CASSERT(p1->num == 1,"");
                DLIB_CASSERT(p11.use_count() == 2,"");
                p1.reset();
                DLIB_CASSERT(p1.get() == 0,"");
                DLIB_CASSERT(p1.use_count() == 0,"");
                DLIB_CASSERT(p1.unique() == false,"");
                DLIB_CASSERT(p11.use_count() == 1,"");
                p11 = p2;
                DLIB_CASSERT(p1.use_count() == 0,"");
                DLIB_CASSERT(p1.unique() == false,"");
                DLIB_CASSERT(p11.use_count() == 3,"");
                DLIB_CASSERT(p11.unique() == false,"");

                // now p11, p2, and p22 all reference the same thing and the rest are null
                DLIB_CASSERT((p11 < p2) == false,"")
                    DLIB_CASSERT((p2 < p11) == false,"")

                    DLIB_CASSERT(get_deleter<D>(p4) == 0,"");
                p4 = p2;
                DLIB_CASSERT(get_deleter<D>(p4) != 0,"");
                DLIB_CASSERT(get_deleter<D>(p4) == get_deleter<D>(p2),"");
                DLIB_CASSERT(get_deleter<D>(p4) == get_deleter<D>(p11),"");
                DLIB_CASSERT(get_deleter<int>(p4) == 0,"");

                realp1 = new derived;
                p1.reset(realp1, &deleter_base);
                DLIB_CASSERT(p1.get() == realp1,"");
                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(*get_deleter<Db>(p1) == &deleter_base,"");
                DLIB_CASSERT(p1 != p4,"");
                p4 = dynamic_pointer_cast<derived>(p1);
                DLIB_CASSERT(!p1.unique(),"");
                DLIB_CASSERT(p1.use_count() == 2,"");
                DLIB_CASSERT(p1 == p4,"");

                realp1 = new derived;
                p1.reset(realp1);
                DLIB_CASSERT(p1.get() == realp1,"");
                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(get_deleter<D>(p1) == 0,"");

                auto_ptr<derived> ap1(new derived);
                auto_ptr<derived> ap2(new derived);
                ap1->num = 35;
                ap2->num = 36;

                DLIB_CASSERT(ap1.get() != 0,"");
                DLIB_CASSERT(ap2.get() != 0,"");
                p1 = ap2;
                p2 = ap1;

                DLIB_CASSERT(ap1.get() == 0,"");
                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(ap2.get() == 0,"");
                DLIB_CASSERT(p2.unique(),"");
                DLIB_CASSERT(p2.use_count() == 1,"");
                DLIB_CASSERT(p1->num == 36,"");
                DLIB_CASSERT(p2->num == 35,"");

            }

            DLIB_CASSERT(counter == 0,counter);
            DLIB_CASSERT(deleter_called == 2,counter);

            weak_ptr<base> wp4;
            {
                shared_ptr<derived> p1(new derived, &deleter_base);
                shared_ptr<derived> p2;
                shared_ptr<base> p3;

                weak_ptr<derived> wp1;
                weak_ptr<base> wp2;
                weak_ptr<base> wp3;

                weak_ptr<derived> wp1c(p1);
                weak_ptr<base> wp2c(p1);
                weak_ptr<base> wp3c(p2);

                DLIB_CASSERT(wp1c.use_count() == 1,"");
                DLIB_CASSERT(wp1c.lock() == p1,"");
                DLIB_CASSERT(wp1c.expired() == false,"");

                DLIB_CASSERT(wp2c.use_count() == 1,"");
                DLIB_CASSERT(wp2c.lock() == p1,"");
                DLIB_CASSERT(wp2c.expired() == false,"");

                DLIB_CASSERT(wp3c.use_count() == 0,"");
                DLIB_CASSERT(wp3c.lock() == shared_ptr<base>(),"");
                DLIB_CASSERT(wp3c.expired() == true,"");

                DLIB_CASSERT(wp2.use_count() == 0,"");
                DLIB_CASSERT(wp2.expired() == true,"");
                DLIB_CASSERT(wp2.lock().use_count() == 0,"");
                DLIB_CASSERT(wp2.lock().unique() == false,"");

                wp1 = p1;
                wp2 = wp1;
                wp3 = p1;

                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(wp1.use_count() == 1,"");
                DLIB_CASSERT(wp2.use_count() == 1,"");
                DLIB_CASSERT(wp3.use_count() == 1,"");
                DLIB_CASSERT(wp1.expired() == false,"");
                DLIB_CASSERT(wp2.expired() == false,"");
                DLIB_CASSERT(wp3.expired() == false,"");
                DLIB_CASSERT(wp1.lock() == p1,"");
                DLIB_CASSERT(wp2.lock() == p1,"");
                DLIB_CASSERT(wp3.lock() == p1,"");

                wp3.reset();

                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(p1.unique(),"");
                DLIB_CASSERT(wp1.use_count() == 1,"");
                DLIB_CASSERT(wp2.use_count() == 1,"");
                DLIB_CASSERT(wp3.use_count() == 0,"");
                DLIB_CASSERT(wp1.expired() == false,"");
                DLIB_CASSERT(wp2.expired() == false,"");
                DLIB_CASSERT(wp3.expired() == true,"");
                DLIB_CASSERT(wp1.lock() == p1,"");
                DLIB_CASSERT(wp2.lock() == p1,"");
                DLIB_CASSERT(wp3.lock() == shared_ptr<base>(),"");

                p1.reset();

                DLIB_CASSERT(p1.use_count() == 0,"");
                DLIB_CASSERT(p1.unique() == false,"");
                DLIB_CASSERT(wp1.use_count() == 0,"");
                DLIB_CASSERT(wp2.use_count() == 0,"");
                DLIB_CASSERT(wp3.use_count() == 0,"");
                DLIB_CASSERT(wp1.expired() == true,"");
                DLIB_CASSERT(wp2.expired() == true,"");
                DLIB_CASSERT(wp3.expired() == true,"");
                DLIB_CASSERT(wp1.lock() == shared_ptr<base>(),"");
                DLIB_CASSERT(wp2.lock() == shared_ptr<base>(),"");
                DLIB_CASSERT(wp3.lock() == shared_ptr<base>(),"");

                p1.reset(new derived);

                DLIB_CASSERT(p1.use_count() == 1,"");
                DLIB_CASSERT(p1.unique() == true,"");
                DLIB_CASSERT(wp1.use_count() == 0,"");
                DLIB_CASSERT(wp2.use_count() == 0,"");
                DLIB_CASSERT(wp3.use_count() == 0,"");
                DLIB_CASSERT(wp1.expired() == true,"");
                DLIB_CASSERT(wp2.expired() == true,"");
                DLIB_CASSERT(wp3.expired() == true,"");
                DLIB_CASSERT(wp1.lock() == shared_ptr<base>(),"");
                DLIB_CASSERT(wp2.lock() == shared_ptr<base>(),"");
                DLIB_CASSERT(wp3.lock() == shared_ptr<base>(),"");

                DLIB_CASSERT(wp4.expired() == true,"");
                DLIB_CASSERT(wp4.lock() == shared_ptr<base>(),"");
                wp4 = p1;
                p3 = p1;
                DLIB_CASSERT(wp4.expired() == false,"");
                DLIB_CASSERT(wp4.lock() == p3,"");

                bool ok = false;
                try {
                    shared_ptr<base> bad_ptr(wp1);
                } catch (bad_weak_ptr&)
                {
                    ok = true;
                }
                DLIB_CASSERT(ok,"");
            }
            DLIB_CASSERT(wp4.expired() == true,"");
            DLIB_CASSERT(wp4.lock() == shared_ptr<base>(),"");

            DLIB_CASSERT(counter == 0,counter);
            DLIB_CASSERT(deleter_called == 3,counter);

        }

        class smart_pointers_tester : public tester
        {
        public:
            smart_pointers_tester (
            ) :
                tester ("test_smart_pointers",
                        "Runs tests on the smart pointers.")
            {}

            void perform_test (
            )
            {
                smart_pointers_test();
            }
        } a;

    }