Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
RAFA91
Заблокирован
#1

Реализация интеллектуального указателя подсчета ссылок - C++

07.11.2015, 16:11. Просмотров 710. Ответов 16
Метки нет (Все метки)

Добрый день !
Подскажите пожалуйста, правильно ли я реализовал интеллектуальный указатель подсчета ссылок ?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// Smart_Pointers.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
template <class T>
class Pointer
{
    T *p;
    static int counter;
public:
    Pointer(T *_p) : p(_p) 
    {
        cout<<"constructor Pointer "<<this<<endl;
        counter++;
    }
    ~Pointer()  
    {
        cout<<"destructor Pointer "<<this<<endl;
        counter--;
        if(!counter) delete p;
    }
    Pointer(const Pointer &rhs) 
    {
        cout<<"constructor copy Pointer "<<this<<" "<<&rhs<<endl;
        counter++;
        p = rhs.p;
    }
};
 
template <class T>
int Pointer<T>::counter=0;
 
class Cat
{
    public:
    Cat()  {cout<<"constructor Cat "<<this<<endl;}
    ~Cat()  {cout<<"destructor Cat "<<this<<endl;}
};
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    Pointer<Cat> Murzik(new Cat);
    {
        cout<<"1: ))))))))))))"<<endl;
        Pointer<Cat> Manka(Murzik);
        cout<<"1: ((((((((((((("<<endl;
        {
            cout<<"2: ))))))))))))"<<endl;
            Pointer<Cat> Borya(Manka);
            cout<<"2: ((((((((((((("<<endl;
        }
    }
    cout<<"###############################"<<endl;
 
    return 0;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.11.2015, 16:11
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Реализация интеллектуального указателя подсчета ссылок (C++):

Реализация умного указателя - C++
Добрый вечер. Сегодня с умным указателем поиграться. Написал обгортку : #pragma once template &lt;typename T&gt; class UniquePtr { ...

Реализация вектора ссылок - C++
Доброго времени суток, дорогие форумчане! Проблема в следующем: мне дано было задание сделать игру Го(кто не знает это что-то вроде...

Реализация программы с использованием ссылок и указателей - C++
Добрые люди! Подскажите, есть ли тут использованные ссылки и указатели? Препод не принимает лабораторную работу, пока я не реализую...

Почему увеличение указателя на sizeof(тип) не тождественно инкременту этого же указателя? - C++
Всем доброго дня.:) Можете обьяснить ,почему при инкриментировании указателя,его значение(адресс) увеличивается на 4 (размер int в...

Как сделать функцию от указателя на класс и указателя на метод? - C++
Не получается сделать функцию, параметрами которой являются указатель на класс и на метод. Обращаться к классу нужно именно по указателю,...

Преобразование кода без указателя в код с использованием указателя - C++
Правильно ли выполнил? Исходный код без указателя #include &lt;iostream&gt; #include &lt;cstdlib&gt; #include &lt;fstream&gt; using namespace...

16
castaway
Эксперт С++
4915 / 3023 / 370
Регистрация: 10.11.2010
Сообщений: 11,081
Записей в блоге: 10
Завершенные тесты: 1
07.11.2015, 16:42 #2
Для сравнения.
Вывод твоего примера
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
constructor Cat 0x6d7408
constructor Pointer 0x28fec0
1: ))))))))))))
constructor copy Pointer 0x28febc 0x28fec0
1: (((((((((((((
2: ))))))))))))
constructor copy Pointer 0x28feb8 0x28febc
2: (((((((((((((
destructor Pointer 0x28feb8
destructor Pointer 0x28febc
###############################
destructor Pointer 0x28fec0
destructor Cat 0x6d7408
Вывод примера с использованием IntrusiveRefCntPtr из LLVM
Bash
1
2
3
4
5
6
7
constructor Cat 0x707408
1: ))))))))))))
1: (((((((((((((
2: ))))))))))))
2: (((((((((((((
###############################
 destructor Cat 0x707408
Пример с использованием IntrusiveRefCntPtr из LLVM
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include "IntrusiveRefCntPtr.h"
 
class Cat : public llvm::RefCountedBase <Cat> {
public:
     Cat() { std::cout << "constructor Cat " << this << std::endl; }
    ~Cat() { std::cout << " destructor Cat " << this << std::endl; }
};
 
int main()
{
    llvm::IntrusiveRefCntPtr <Cat> Murzik( new Cat );
    {
        std::cout << "1: ))))))))))))" << std::endl;
        llvm::IntrusiveRefCntPtr<Cat> Manka( Murzik );
        std::cout << "1: (((((((((((((" << std::endl;
        {
            std::cout << "2: ))))))))))))" << std::endl;
            llvm::IntrusiveRefCntPtr<Cat> Borya( Manka );
            std::cout << "2: (((((((((((((" << std::endl;
        }
    }
    std::cout << "###############################" << std::endl;
    return 0;
}
IntrusiveRefCntPtr.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
//== llvm/ADT/IntrusiveRefCntPtr.h - Smart Refcounting Pointer ---*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines IntrusiveRefCntPtr, a template class that
// implements a "smart" pointer for objects that maintain their own
// internal reference count, and RefCountedBase/RefCountedBaseVPTR, two
// generic base classes for objects that wish to have their lifetimes
// managed using reference counting.
//
// IntrusiveRefCntPtr is similar to Boost's intrusive_ptr with added
// LLVM-style casting.
//
//===----------------------------------------------------------------------===//
 
#ifndef LLVM_ADT_INTRUSIVEREFCNTPTR_H
#define LLVM_ADT_INTRUSIVEREFCNTPTR_H
 
#include <atomic>
#include <cassert>
#include <cstddef>
 
namespace llvm {
 
  template <class T>
  class IntrusiveRefCntPtr;
 
//===----------------------------------------------------------------------===//
/// RefCountedBase - A generic base class for objects that wish to
///  have their lifetimes managed using reference counts. Classes
///  subclass RefCountedBase to obtain such functionality, and are
///  typically handled with IntrusiveRefCntPtr "smart pointers" (see below)
///  which automatically handle the management of reference counts.
///  Objects that subclass RefCountedBase should not be allocated on
///  the stack, as invoking "delete" (which is called when the
///  reference count hits 0) on such objects is an error.
//===----------------------------------------------------------------------===//
  template <class Derived>
  class RefCountedBase {
    mutable unsigned ref_cnt;
 
  public:
    RefCountedBase() : ref_cnt(0) {}
    RefCountedBase(const RefCountedBase &) : ref_cnt(0) {}
 
    void Retain() const { ++ref_cnt; }
    void Release() const {
      assert (ref_cnt > 0 && "Reference count is already zero.");
      if (--ref_cnt == 0) delete static_cast<const Derived*>(this);
    }
  };
 
//===----------------------------------------------------------------------===//
/// RefCountedBaseVPTR - A class that has the same function as
///  RefCountedBase, but with a virtual destructor. Should be used
///  instead of RefCountedBase for classes that already have virtual
///  methods to enforce dynamic allocation via 'new'. Classes that
///  inherit from RefCountedBaseVPTR can't be allocated on stack -
///  attempting to do this will produce a compile error.
//===----------------------------------------------------------------------===//
  class RefCountedBaseVPTR {
    mutable unsigned ref_cnt;
    virtual void anchor();
 
  protected:
    RefCountedBaseVPTR() : ref_cnt(0) {}
    RefCountedBaseVPTR(const RefCountedBaseVPTR &) : ref_cnt(0) {}
 
    virtual ~RefCountedBaseVPTR() {}
 
    void Retain() const { ++ref_cnt; }
    void Release() const {
      assert (ref_cnt > 0 && "Reference count is already zero.");
      if (--ref_cnt == 0) delete this;
    }
 
    template <typename T>
    friend struct IntrusiveRefCntPtrInfo;
  };
 
 
  template <typename T> struct IntrusiveRefCntPtrInfo {
    static void retain(T *obj) { obj->Retain(); }
    static void release(T *obj) { obj->Release(); }
  };
 
/// \brief A thread-safe version of \c llvm::RefCountedBase.
///
/// A generic base class for objects that wish to have their lifetimes managed
/// using reference counts. Classes subclass \c ThreadSafeRefCountedBase to
/// obtain such functionality, and are typically handled with
/// \c IntrusiveRefCntPtr "smart pointers" which automatically handle the
/// management of reference counts.
template <class Derived>
class ThreadSafeRefCountedBase {
  mutable std::atomic<int> RefCount;
 
protected:
  ThreadSafeRefCountedBase() : RefCount(0) {}
 
public:
  void Retain() const { ++RefCount; }
 
  void Release() const {
    int NewRefCount = --RefCount;
    assert(NewRefCount >= 0 && "Reference count was already zero.");
    if (NewRefCount == 0)
      delete static_cast<const Derived*>(this);
  }
};
 
//===----------------------------------------------------------------------===//
/// IntrusiveRefCntPtr - A template class that implements a "smart pointer"
///  that assumes the wrapped object has a reference count associated
///  with it that can be managed via calls to
///  IntrusivePtrAddRef/IntrusivePtrRelease.  The smart pointers
///  manage reference counts via the RAII idiom: upon creation of
///  smart pointer the reference count of the wrapped object is
///  incremented and upon destruction of the smart pointer the
///  reference count is decremented.  This class also safely handles
///  wrapping NULL pointers.
///
/// Reference counting is implemented via calls to
///  Obj->Retain()/Obj->Release(). Release() is required to destroy
///  the object when the reference count reaches zero. Inheriting from
///  RefCountedBase/RefCountedBaseVPTR takes care of this
///  automatically.
//===----------------------------------------------------------------------===//
  template <typename T>
  class IntrusiveRefCntPtr {
    T* Obj;
 
  public:
    typedef T element_type;
 
    explicit IntrusiveRefCntPtr() : Obj(nullptr) {}
 
    IntrusiveRefCntPtr(T* obj) : Obj(obj) {
      retain();
    }
 
    IntrusiveRefCntPtr(const IntrusiveRefCntPtr& S) : Obj(S.Obj) {
      retain();
    }
 
    IntrusiveRefCntPtr(IntrusiveRefCntPtr&& S) : Obj(S.Obj) {
      S.Obj = nullptr;
    }
 
    template <class X>
    IntrusiveRefCntPtr(IntrusiveRefCntPtr<X>&& S) : Obj(S.get()) {
      S.Obj = 0;
    }
 
    template <class X>
    IntrusiveRefCntPtr(const IntrusiveRefCntPtr<X>& S)
      : Obj(S.get()) {
      retain();
    }
 
    IntrusiveRefCntPtr& operator=(IntrusiveRefCntPtr S) {
      swap(S);
      return *this;
    }
 
    ~IntrusiveRefCntPtr() { release(); }
 
    T& operator*() const { return *Obj; }
 
    T* operator->() const { return Obj; }
 
    T* get() const { return Obj; }
 
    explicit operator bool() const { return Obj; }
 
    void swap(IntrusiveRefCntPtr& other) {
      T* tmp = other.Obj;
      other.Obj = Obj;
      Obj = tmp;
    }
 
    void reset() {
      release();
      Obj = nullptr;
    }
 
    void resetWithoutRelease() {
      Obj = 0;
    }
 
  private:
    void retain() { if (Obj) IntrusiveRefCntPtrInfo<T>::retain(Obj); }
    void release() { if (Obj) IntrusiveRefCntPtrInfo<T>::release(Obj); }
 
    template <typename X>
    friend class IntrusiveRefCntPtr;
  };
 
  template<class T, class U>
  inline bool operator==(const IntrusiveRefCntPtr<T>& A,
                         const IntrusiveRefCntPtr<U>& B)
  {
    return A.get() == B.get();
  }
 
  template<class T, class U>
  inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
                         const IntrusiveRefCntPtr<U>& B)
  {
    return A.get() != B.get();
  }
 
  template<class T, class U>
  inline bool operator==(const IntrusiveRefCntPtr<T>& A,
                         U* B)
  {
    return A.get() == B;
  }
 
  template<class T, class U>
  inline bool operator!=(const IntrusiveRefCntPtr<T>& A,
                         U* B)
  {
    return A.get() != B;
  }
 
  template<class T, class U>
  inline bool operator==(T* A,
                         const IntrusiveRefCntPtr<U>& B)
  {
    return A == B.get();
  }
 
  template<class T, class U>
  inline bool operator!=(T* A,
                         const IntrusiveRefCntPtr<U>& B)
  {
    return A != B.get();
  }
 
  template <class T>
  bool operator==(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
    return !B;
  }
 
  template <class T>
  bool operator==(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
    return B == A;
  }
 
  template <class T>
  bool operator!=(std::nullptr_t A, const IntrusiveRefCntPtr<T> &B) {
    return !(A == B);
  }
 
  template <class T>
  bool operator!=(const IntrusiveRefCntPtr<T> &A, std::nullptr_t B) {
    return !(A == B);
  }
 
//===----------------------------------------------------------------------===//
// LLVM-style downcasting support for IntrusiveRefCntPtr objects
//===----------------------------------------------------------------------===//
 
  template <typename From> struct simplify_type;
 
  template<class T> struct simplify_type<IntrusiveRefCntPtr<T> > {
    typedef T* SimpleType;
    static SimpleType getSimplifiedValue(IntrusiveRefCntPtr<T>& Val) {
      return Val.get();
    }
  };
 
  template<class T> struct simplify_type<const IntrusiveRefCntPtr<T> > {
    typedef /*const*/ T* SimpleType;
    static SimpleType getSimplifiedValue(const IntrusiveRefCntPtr<T>& Val) {
      return Val.get();
    }
  };
 
} // end namespace llvm
 
#endif // LLVM_ADT_INTRUSIVEREFCNTPTR_H


Разница лишь в том, что IntrusiveRefCntPtr интрузивный.
2
RAFA91
Заблокирован
07.11.2015, 16:58  [ТС] #3
castaway я спросил про правильность реализации. как устроен библиотечный понятия не имею .

в книге не была представлена реализация а только описание.

исходя из этого описания я и накалякал этот указатель. вот и спрашиваю правильно ли я его реализовал.

Цитата Сообщение от castaway Посмотреть сообщение
интрузивный.

это как ?
0
Миниатюры
Реализация интеллектуального указателя подсчета ссылок  
castaway
Эксперт С++
4915 / 3023 / 370
Регистрация: 10.11.2010
Сообщений: 11,081
Записей в блоге: 10
Завершенные тесты: 1
07.11.2015, 17:04 #4
Цитата Сообщение от RAFA91 Посмотреть сообщение
вот и спрашиваю правильно ли я его реализовал.
А он работает?
0
Kastaneda
Jesus loves me
Эксперт С++
4689 / 2893 / 236
Регистрация: 12.12.2009
Сообщений: 7,356
Записей в блоге: 2
Завершенные тесты: 1
07.11.2015, 17:22 #5
main реализована не корректно - при правильной и не правильной реализации указателя вывод будет одинаковый.
Цитата Сообщение от RAFA91 Посмотреть сообщение
правильно ли я его реализовал.
Нет, утечка памяти будет.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
07.11.2015, 17:28 #6
Цитата Сообщение от RAFA91 Посмотреть сообщение
вот и спрашиваю правильно ли я его реализовал
Неправильно.
Хотя бы потому, что counter - статический.

Вопрос на засыпку. Что будет в таком коде?
C++
1
2
3
4
5
6
7
8
9
10
11
int _tmain(int argc, _TCHAR* argv[])
{
    Pointer<Cat> Murzik(new Cat);
    {
        Pointer<Cat> Manka(Murzik);
        Pointer<Cat> Borya(new Cat);
        Pointer<Cat> Vasya(Borya);
    }
 
    return 0;
}
Добавлено через 3 минуты
Цитата Сообщение от RAFA91 Посмотреть сообщение
как устроен библиотечный понятия не имею
На самом деле с этого нужно было начать.
Изучить как реализован библиотечный.
Может быть ты на это месяц потратишь, зато узнаешь гораздо больше всего нового.
1
RAFA91
Заблокирован
07.11.2015, 17:43  [ТС] #7
[
Цитата Сообщение от castaway Посмотреть сообщение
А он работает?
а что вам мешает его запустить

Цитата Сообщение от DrOffset Посмотреть сообщение
Хотя бы потому, что counter - статический.
и что ? я захотел применить статику

Цитата Сообщение от DrOffset Посмотреть сообщение
Pointer<Cat> Borya(new Cat);
значит надо искать другое решение.
0
Kastaneda
Jesus loves me
Эксперт С++
4689 / 2893 / 236
Регистрация: 12.12.2009
Сообщений: 7,356
Записей в блоге: 2
Завершенные тесты: 1
07.11.2015, 17:46 #8
Цитата Сообщение от RAFA91 Посмотреть сообщение
и что ? я захотел применить статику
Используя твой указатель я могу 100 раз выделить память, но delete будет вызван только 1 раз.
0
DrOffset
7376 / 4453 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
07.11.2015, 17:48 #9
Цитата Сообщение от RAFA91 Посмотреть сообщение
и что ? я захотел применить статику
Ну подумай что.
Объектов может быть много, а счетчик на всех один.
0
castaway
Эксперт С++
4915 / 3023 / 370
Регистрация: 10.11.2010
Сообщений: 11,081
Записей в блоге: 10
Завершенные тесты: 1
07.11.2015, 17:49 #10
Цитата Сообщение от RAFA91 Посмотреть сообщение
а что вам мешает его запустить
Вопрос не ко мне. Что мешает запустить его тебе, и проверить как он работает?
0
RAFA91
Заблокирован
07.11.2015, 18:11  [ТС] #11
Цитата Сообщение от castaway Посмотреть сообщение
Вопрос не ко мне. Что мешает запустить его тебе, и проверить как он работает?
ошибок в компиляции хоть не было. но утечка всеравно будет. DrOffset меня в этом убедил.

а что если так ?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Smart_Pointers.cpp : Defines the entry point for the console application.
//
 
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
template <class T>
class Pointer
{
    T *p;
    int counter;
    Pointer *k;
public:
    Pointer(T *_p) : p(_p),counter(1),k(NULL) 
    {
        cout<<"constructor Pointer "<<this<<endl;
    }
    ~Pointer()  
    {
        cout<<"destructor Pointer "<<this<<endl;
        if (k) (k->counter)--;
        counter--;
        if(!counter && !k) delete p;
    }
    Pointer(Pointer &rhs) 
    {
        cout<<"constructor copy Pointer "<<this<<" "<<&rhs<<endl;
        rhs.counter++;
        counter = 1;
        k = &rhs;
        p = rhs.p;
    }
};
 
 
class Cat
{
    public:
    Cat()  {cout<<"constructor Cat "<<this<<endl;}
    ~Cat()  {cout<<"destructor Cat "<<this<<endl;}
};
 
 
int _tmain(int argc, _TCHAR* argv[])
{
    Pointer<Cat> Murzik(new Cat);
    {
        cout<<"1: ))))))))))))"<<endl;
        Pointer<Cat> Manka(Murzik);
        cout<<"1: ((((((((((((("<<endl;
        {
            cout<<"2: ))))))))))))"<<endl;
            Pointer<Cat> Borya(Manka);
            cout<<"2: ((((((((((((("<<endl;
        }
    }
    cout<<"###############################"<<endl;
 
    return 0;
}
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
07.11.2015, 18:27 #12
Цитата Сообщение от RAFA91 Посмотреть сообщение
а что если так ?
шняга жеж.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Pointer
{
    T *p;
    std::atomic<size_t*> counter; //<--- смарты шарят общий только для них счетчик
    ...
};
...
 
 
int main()
{
    Pointer<int> p1 = new int;
    Pointer<int> p2 = p1;
 
    Pointer<int> p3 = new int;
    Pointer<int> p4 = p3;
 
    //p1 и p2 шарят один счетчик
    //p3 и p4 шарят другой счетчик
 
   //p1,p2 не имеют никакого отношения к p3,p4
}
Реализуйте класс SharedPtr
0
RAFA91
Заблокирован
08.11.2015, 15:15  [ТС] #13
Цитата Сообщение от hoggy Посмотреть сообщение
шняга жеж.
теперь же утечки вроде нету. или можете доказать обратное ?
Цитата Сообщение от hoggy Посмотреть сообщение
/p1 и p2 шарят один счетчик
все правильно p1 имеет счетчик , которым управляет p2

Добавлено через 7 минут
у p2 свой счетчик который не несет никакой информации.

вся фишка в этом
C++
1
if(!counter && !k) delete p;
для p2 оно не выполняется так как k не равно нулю.
0
hoggy
6701 / 2883 / 494
Регистрация: 15.11.2014
Сообщений: 6,480
Завершенные тесты: 1
08.11.2015, 16:16 #14
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от RAFA91 Посмотреть сообщение
теперь же утечки вроде нету.
навскидку обнаружено:

1.
многочисленные нарушения граммар-конст,
которые провоцируют ошибки компиляции.

например, нельзя проинициализировать смарт временным объектом:

C++
1
2
3
4
5
6
7
8
9
Pointer<Cat> compile_error()  //<--- возвращает по значению
{
    return new Cat;
}
 
int main()
{
    Pointer<Cat> p = compile_error(); // upppssssss
}
2.
подсчет ссылок работает неверно.

см тест:
http://ideone.com/iTbrby

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <cassert>
#include <cstddef>
#include <atomic>
 
#undef dVIEWNUMBERS
 
#ifdef dVIEWNUMBERS
    #ifndef _IOSTREAM_
        #error include <iostream> first    
    #endif
    #undef dVIEWNUMBERS
    #define dVIEWNUMBERS \
        std::cout << "instances = " << Instances() << std::endl;
#else
    #define dVIEWNUMBERS
#endif
 
namespace tools{
 
    // счетчик созданных экземпляров класса
    template<class T> class Copies
    {
        typedef std::atomic<size_t>
            count_t;
    public:
 
        ~Copies()
        {
            // количество вызванных деструкторов больше, 
            // чем количество предшествующих им конструкторов
            // (возможная причина такой неисправности - 
            // запуск диструктора ресурса в многопоточной среде)
            assert( NumInstances() > 0 && 
                "ERROR: DESTRUCTOR CALLED WITHOUT CONSTRUCTOR" );
 
            --NumInstances(); 
            dVIEWNUMBERS; 
        }
 
        Copies()              { ++NumInstances(); dVIEWNUMBERS; }
        Copies(const Copies&) { ++NumInstances(); dVIEWNUMBERS; }
        Copies(Copies&&)      { ++NumInstances(); dVIEWNUMBERS; }
 
        static size_t Instances() { return NumInstances(); }
    private:
        static count_t& NumInstances()
        { static count_t n(0); return n; }
    };
 
}// namespace tools
 
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
 
#include <iostream>
 
using namespace std;
 
template <class T>
class Pointer
{
    T *p;
    int counter;
    Pointer *k;
public:
    Pointer(T *_p) : p(_p),counter(1),k(NULL) 
    {}
    ~Pointer()  
    {
        if (k) (k->counter)--;
        counter--;
        if(!counter && !k) delete p;
    }
    Pointer(Pointer &rhs) 
    {
        rhs.counter++;
        counter = 1;
        k = &rhs;
        p = rhs.p;
    }
 
    T* operator->() { return p; }
 
    int users()const { return counter; }
};
 
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
 
struct ICat
{
    // <--- отсутствует виртуальный диструктор
    // однако несмотря на это
    // смарт-поинтер должен суметь 
    // позвать диструктор наследника
 
    // --- виртуальную функцию задействуем
    // что бы проверить ресурс смарт-поинтера на
    // консистентность
    // в случае невалидного указателя на vtbl
    // скорее всего получим краш времени выполнения
    virtual void foo()const=0;
};
 
class Cat : public ICat, public tools::Copies<ICat>
{
public:
    Cat()           { cout << "ctor Cat " << this << endl; }
    Cat(const Cat&) { cout << "copy Cat " << this << endl; }
    Cat(Cat&&)      { cout << "move Cat " << this << endl; }
   ~Cat()           {cout  << "dtor Cat " << this << endl; }
    virtual void foo()const { std::cout <<"cat\n"; }
};
 
 
int main()
{
    std::cout << "hello, world\n";
 
    {
        // --- тест на конкретный тип ресурса
 
        Pointer<Cat> p1(new Cat);
        assert(p1.users()==1 && "ERROR: INVALID COUNTER" );
 
        Pointer<Cat> p2 = p1;
        assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
        assert(p2.users()==2 && "ERROR: INVALID COUNTER" );
 
        assert(Cat::Instances()==1 && "LOGIC ERROR");
 
 
        p1->foo();
        p2->foo();
 
        Pointer<Cat> p3(new Cat);
        assert(p3.users()==1 && "ERROR: INVALID COUNTER" );
        Pointer<Cat> p4 = p3;
 
        assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
        assert(p2.users()==2 && "ERROR: INVALID COUNTER" );
        assert(p3.users()==2 && "ERROR: INVALID COUNTER" );
        assert(p4.users()==2 && "ERROR: INVALID COUNTER" );
 
        assert(Cat::Instances()==2 && "LOGIC ERROR");
 
        p3->foo();
        p4->foo();
    }
    assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
    {
        // --- тест работы с интерфейсом
 
        Pointer<ICat> p1(new Cat);
        Pointer<ICat> p2 = p1;
 
        assert(Cat::Instances()==1 && "LOGIC ERROR");
 
        p1->foo();
        p2->foo();
 
        Pointer<Cat> p3(new Cat);
        Pointer<Cat> p4 = p3;
 
        assert(Cat::Instances()==2 && "LOGIC ERROR");
 
        p3->foo();
        p4->foo();
    }
    assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
}
prog: prog.cpp:142: int main(): Assertion `p2.users()==2 && "ERROR: INVALID COUNTER"' failed.
3.
если отключить ассерт-проверки счетчика ссылок,
тогда поимеем учетку памяти на тесте интерфейса:
http://ideone.com/K7tlDw

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <cassert>
#include <cstddef>
#include <atomic>
 
#undef dVIEWNUMBERS
 
#ifdef dVIEWNUMBERS
    #ifndef _IOSTREAM_
        #error include <iostream> first    
    #endif
    #undef dVIEWNUMBERS
    #define dVIEWNUMBERS \
        std::cout << "instances = " << Instances() << std::endl;
#else
    #define dVIEWNUMBERS
#endif
 
namespace tools{
 
    // счетчик созданных экземпляров класса
    template<class T> class Copies
    {
        typedef std::atomic<size_t>
            count_t;
    public:
 
        ~Copies()
        {
            // количество вызванных деструкторов больше, 
            // чем количество предшествующих им конструкторов
            // (возможная причина такой неисправности - 
            // запуск диструктора ресурса в многопоточной среде)
            assert( NumInstances() > 0 && 
                "ERROR: DESTRUCTOR CALLED WITHOUT CONSTRUCTOR" );
 
            --NumInstances(); 
            dVIEWNUMBERS; 
        }
 
        Copies()              { ++NumInstances(); dVIEWNUMBERS; }
        Copies(const Copies&) { ++NumInstances(); dVIEWNUMBERS; }
        Copies(Copies&&)      { ++NumInstances(); dVIEWNUMBERS; }
 
        static size_t Instances() { return NumInstances(); }
    private:
        static count_t& NumInstances()
        { static count_t n(0); return n; }
    };
 
}// namespace tools
 
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
 
#include <iostream>
 
using namespace std;
 
template <class T>
class Pointer
{
    T *p;
    int counter;
    Pointer *k;
public:
    Pointer(T *_p) : p(_p),counter(1),k(NULL) 
    {}
    ~Pointer()  
    {
        if (k) (k->counter)--;
        counter--;
        if(!counter && !k) delete p;
    }
    Pointer(Pointer &rhs) 
    {
        rhs.counter++;
        counter = 1;
        k = &rhs;
        p = rhs.p;
    }
 
    T* operator->() { return p; }
 
    int users()const { return counter; }
};
 
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
 
struct ICat
{
    // <--- отсутствует виртуальный диструктор
    // однако несмотря на это
    // смарт-поинтер должен суметь 
    // позвать диструктор наследника
 
    // --- виртуальную функцию задействуем
    // что бы проверить ресурс смарт-поинтера на
    // консистентность
    // в случае невалидного указателя на vtbl
    // скорее всего получим краш времени выполнения
    virtual void foo()const=0;
};
 
class Cat : public ICat, public tools::Copies<ICat>
{
public:
    Cat()           { cout << "ctor Cat " << this << endl; }
    Cat(const Cat&) { cout << "copy Cat " << this << endl; }
    Cat(Cat&&)      { cout << "move Cat " << this << endl; }
   ~Cat()           {cout  << "dtor Cat " << this << endl; }
    virtual void foo()const { std::cout <<"cat\n"; }
};
 
 
int main()
{
    std::cout << "hello, world\n";
 
    {
        // --- тест на конкретный тип ресурса
 
        Pointer<Cat> p1(new Cat);
        Pointer<Cat> p2 = p1;
 
        assert(Cat::Instances()==1 && "LOGIC ERROR");
 
        p1->foo();
        p2->foo();
 
        Pointer<Cat> p3(new Cat);
        Pointer<Cat> p4 = p3;
 
        assert(Cat::Instances()==2 && "LOGIC ERROR");
 
        p3->foo();
        p4->foo();
    }
    assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
    {
        // --- тест работы с интерфейсом
 
        Pointer<ICat> p1(new Cat);
        Pointer<ICat> p2 = p1;
 
        assert(Cat::Instances()==1 && "LOGIC ERROR");
 
        p1->foo();
        p2->foo();
 
        Pointer<Cat> p3(new Cat);
        Pointer<Cat> p4 = p3;
 
        assert(Cat::Instances()==2 && "LOGIC ERROR");
 
        p3->foo();
        p4->foo();
    }
    assert(Cat::Instances()==0 && "DETECTED MEMORY LEAK");
}
prog: prog.cpp:171: int main(): Assertion `Cat::Instances()==0 && "DETECTED MEMORY LEAK"' failed.
4.
если исправить ошибки компиляции (см пунк 1),
тогда утечки памяти сможет зафиксировать
и тест на работу с конкретным типом тоже.

однако проиллюстрировать это нет возможности,
поскольку ошибки компиляции не позволяют запустить приложение,
и прогнать механизм по тестам.

Цитата Сообщение от RAFA91 Посмотреть сообщение
можете доказать обратное ?
я никогда ничего никому не доказываю,
если не имею с этого прямой выгоды.
(например - деньги).

1.
код, который вы написали можно выбросить в мусорное ведро.
ваша ошибка не в стиле кода, и не в реализации
(хотя тут конечно много проблем).
а в самом подходе к разработке.
об этом ниже:

2.
разработка механизмов общего назначения
(к категории которой относится смарт-поинтер, например),
предполагают наличие качественного тестирования.

рекомендую вам ознакомиться с методикой TDD,
и открыть для себя gmock/gtest (и подобные инструментальные средства).

если вы освоите этот замечательный подход к разработке,
то у вас никогда больше не возникнет повода просить доказательств,
или испытывать затруднений с их предоставлением.

если вкратце:
вы создаете консольное приложение,
задача которого проиллюстрировать весь функционал
разрабатываемого вами механизма.

при этом, иллюстрируя различные особенности разрабатываемого вами механизма,
вы вписываете различные проверки,
которые контролируют, что механизм делает именно то,
что от него ожидается.

например, вы иллюстрируете,
как один смарт-поинтер расшаривается от другого:

C++
1
2
Pointer<Cat> p1 = new Cat;
Pointer<Cat> p2 = p1;
что при этом должно произойти?
допустим, счетчик ссылок должен увеличиться на 1.

давайте это проконтролируем:

C++
1
2
3
Pointer<Cat> p1 = new Cat;
Pointer<Cat> p2 = p1;
assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
при этом, счетчик ссылок у обоих смартов должен быть одинаковым:

C++
1
2
3
4
Pointer<Cat> p1 = new Cat;
Pointer<Cat> p2 = p1;
assert(p1.users()==2 && "ERROR: INVALID COUNTER" );
assert(p2.users()==2 && "ERROR: INVALID COUNTER" );
один раз напишите тесты для своего детища.
и все вопросы касательно гарантий стабильности его работы сразу отпадут.

в последствии, при модификациях механизма,
эти же самые тесты помогут гарантировать,
что при изменениях нигде ничего не сломалось.

тесты - не панацея.
но в вашем случае, это именно то,
что доктор прописал.
5
RAFA91
Заблокирован
08.11.2015, 17:09  [ТС] #15
hoggy то что вы привели свой вариант кода это конечно здорово. отдельная благодарность.

только так и не показали пальцем что не так то теперь в моем варианте.

DrOffset мне вчера конкретно дал понять что применение статического счетчика приведет к утечки памяти.

к примеру такой проблемы больше нет

Цитата Сообщение от Kastaneda Посмотреть сообщение
Используя твой указатель я могу 100 раз выделить память, но delete будет вызван только 1 раз.
0
08.11.2015, 17:09
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.11.2015, 17:09
Привет! Вот еще темы с ответами:

В чём отличие константного указателя и указателя на константу? - C++
int *const p1 и int const* p2 Объясните мне в чём тут отличие.

Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... - C++
Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... как сделать...

Перезаписать память начиная с указателя Bitmap[1] элементами начиная с указателя Bitmap[0] - C++
Задан массив из 3 указателей Bitmap, по адресу Bitmap необходимо записать 480*640 элементов из массива Bitmap. В последнем цикле for выдает...

Реализация Реферальных Ссылок - PHP
Расскажите (желательно по пунктам) Как Реализуются реферальные ссылки . или если есть статью на существующую


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru