Форум программистов, компьютерный форум CyberForum.ru

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

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.75
DiffEreD
1427 / 764 / 95
Регистрация: 21.06.2011
Сообщений: 1,740
Записей в блоге: 2
#1

shared_ptr и реализация семантики переноса - C++

25.12.2012, 16:21. Просмотров 1622. Ответов 10
Метки нет (Все метки)

Написал небольшой класс Array основанный на std::shared_ptr. Но как то не совсем уверен в правильности реализации конструктора и оператора переноса. Плюс, возникли какие то неполадки с перегруженным оператором + - он почему то модифицирует объекты которых не должен модифицировать. Что в моем коде не правильно?
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
#include <iostream>
#include <algorithm>
#include <iterator>
#include <memory>
#include <functional>
 
template<typename T>
class Array
{
    std::shared_ptr<T> m_array;
    size_t m_size;
public:
    typedef T*          iterator;
    typedef const T*    const_iterator;
    iterator        begin()         {return m_array.get();}
    iterator        end()           {return m_array.get()+m_size;}
    const_iterator  begin() const   {return m_array.get();}
    const_iterator  end()   const   {return m_array.get()+m_size;}
 
    const T operator[](size_t index) const {return *(m_array.get()+index);}
    T operator[](size_t index) {return *(m_array.get()+index);}
 
    explicit Array(size_t size = 0, const T& value = T()) : m_size(size),
        m_array(new T[size], std::default_delete<T[]>())
    {
        std::fill(m_array.get(), m_array.get()+m_size, value);
    }
 
    Array(const Array& obj) : m_size(obj.m_size), m_array(obj.m_array) {std::cout<<"Array(const Array& obj)\n";}
 
    Array(Array&& obj) : m_size(std::move(obj.m_size)), m_array(std::move(obj.m_array))
    {
        std::cout<<"Array(Array&& obj)\n";
        obj.m_size = 0;
        obj.m_array.reset();
    }
 
    Array& operator=(const Array& obj)
    {
        std::cout<<"Array& operator=(const Array& obj)\n";
        if (this == &obj)
            return *this;
        m_size = obj.m_size;
        m_array = obj.m_array;
        return *this;
    }
 
    Array& operator=(Array&& obj)
    {
        std::cout<<"Array& operator=(Array&& obj)\n";
        m_size = std::move(obj.m_size);
        m_array = std::move(obj.m_array);
        obj.m_size = 0;
        obj.m_array.reset();
        return *this;
    }
 
    Array& operator+=(const Array& rhs)
    {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<T>());
        return *this;
    }
 
    Array operator+(const Array& rhs)
    {
        Array ar;
        ar = *this;
        ar+=rhs;
        return ar;
    }
};
 
int main()
{
    {
        Array<int> a1(10, 6);
        Array<int> a2(a1);       //копирующий конструктор
 
 
        /*std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));*/
 
        Array<int> b1(a2);      //копирующий конструктор
        Array<int> b2;
        b2 = a1+a2;            //почему то модифицирует объекты a1, a2 и b1
 
        std::cout<<"\n\n";
        std::copy(b1.begin(), b1.end(), std::ostream_iterator<int>(std::cout," "));
 
        std::cout<<"\n\n";
        std::copy(b2.begin(), b2.end(), std::ostream_iterator<int>(std::cout," "));
 
        std::cout<<"\n\n";
        std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout," "));
 
    }
    std::cout<<"\n\n";
    system("pause");
    return 0;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
25.12.2012, 16:21     shared_ptr и реализация семантики переноса
Посмотрите здесь:

C++ shared_ptr и vector
Наследование от shared_ptr C++
C++ Shared_ptr собственная реализация
shared_ptr с потомками C++
C++ Shared_ptr
C++ Где найти список всех операторов С++ с описанием их семантики?
Weak_ptr и shared_ptr C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
ForEveR
Модератор
Эксперт С++
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
25.12.2012, 16:33     shared_ptr и реализация семантики переноса #2
yuron_477,
C++
1
obj.m_array.reset();
зачем? shared_ptr сам умный, сам это сделает. int перемещать вцелом резона нет, ибо он в любом случае скопируется.)
gray_fox
What a waste!
1253 / 1136 / 54
Регистрация: 21.04.2012
Сообщений: 2,359
Завершенные тесты: 3
25.12.2012, 16:36     shared_ptr и реализация семантики переноса #3
Цитата Сообщение от yuron_477 Посмотреть сообщение
std::move(obj.m_size)
Это ни к чему, пожалуй (std::move).
Цитата Сообщение от yuron_477 Посмотреть сообщение
//почему то модифицирует объекты a1, a2 и b1
Ну так эти объекты ссылаются на один и тот же участок памяти, у тебя же shared_ptr внутри, и ты при конструировании копируешь их, а не то, на что они ссылаются.
DiffEreD
1427 / 764 / 95
Регистрация: 21.06.2011
Сообщений: 1,740
Записей в блоге: 2
25.12.2012, 16:48  [ТС]     shared_ptr и реализация семантики переноса #4
Ну а как сделать чтобы все логически правильно работало, а то что то я никак не соображу?
gray_fox
What a waste!
1253 / 1136 / 54
Регистрация: 21.04.2012
Сообщений: 2,359
Завершенные тесты: 3
25.12.2012, 16:58     shared_ptr и реализация семантики переноса #5
Я бы хранил unique_ptr, в copy c-tor - std::copy, в move c-tor - std::move.

Добавлено через 6 минут
Или можно сделать класс неизменяемым, т.е. никаких операторов с присвоением.
ForEveR
Модератор
Эксперт С++
7958 / 4720 / 319
Регистрация: 24.06.2010
Сообщений: 10,525
Завершенные тесты: 3
25.12.2012, 17:37     shared_ptr и реализация семантики переноса #6
А я бы как-то так сделал. CoW собственно. Не очень хорошо по отношению к безопасности исключений да и copy-swap бы сделать, но лень.

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
#include <iostream>
#include <algorithm>
#include <iterator>
#include <memory>
#include <functional>
 
template<typename T>
class Array
{
    std::shared_ptr<T> m_array;
    size_t m_size;
public:
    typedef T*          iterator;
    typedef const T*    const_iterator;
    iterator        begin()         {return m_array.get();}
    iterator        end()           {return m_array.get()+m_size;}
    const_iterator  begin() const   {return m_array.get();}
    const_iterator  end()   const   {return m_array.get()+m_size;}
 
    const T operator[](size_t index) const {return *(m_array.get()+index);}
    T operator[](size_t index) {return *(m_array.get()+index);}
 
    explicit Array(size_t size = 0, const T& value = T()) : m_size(size),
        m_array(new T[size], std::default_delete<T[]>())
    {
        std::fill(m_array.get(), m_array.get()+m_size, value);
    }
 
    Array(const Array& obj) : m_size(obj.m_size), m_array(obj.m_array) {std::cout<<"Array(const Array& obj)\n";}
 
    Array(Array&& obj) : m_size(obj.m_size), m_array(std::move(obj.m_array))
    {
        std::cout<<"Array(Array&& obj)\n";
        obj.m_size = 0;
    }
 
    Array& operator=(const Array& obj)
    {
        std::cout<<"Array& operator=(const Array& obj)\n";
        if (this == &obj)
            return *this;
        m_size = obj.m_size;
        m_array = obj.m_array;
        return *this;
    }
 
    Array& operator=(Array&& obj)
    {
        std::cout<<"Array& operator=(Array&& obj)\n";
        m_size = obj.m_size;
        m_array = std::move(obj.m_array);
        obj.m_size = 0;
        return *this;
    }
 
    Array& operator+=(const Array& rhs)
    {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<T>());
        return *this;
    }
 
    Array operator+(const Array& rhs)
    {
        Array ar = deep_copy();
        ar+=rhs;
        return ar;
    }
private:
    Array deep_copy()
    {
       Array ar;
       ar.m_array = std::shared_ptr<T>(new T[m_size], std::default_delete<T[]>());
       const T* array = m_array.get();
       std::copy(array, array + m_size, ar.m_array.get());
       ar.m_size = m_size;
       return ar;
    }
};
 
int main()
{
    {
        Array<int> a1(10, 6);
        Array<int> a2(a1);       //копирующий конструктор
 
 
        /*std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));*/
 
        Array<int> b1(a2);      //копирующий конструктор
        Array<int> b2;
        b2 = a1+a2;            //почему то модифицирует объекты a1, a2 и b1
 
        std::cout<<"\n\n";
        std::copy(b1.begin(), b1.end(), std::ostream_iterator<int>(std::cout," "));
 
        std::cout<<"\n\n";
        std::copy(b2.begin(), b2.end(), std::ostream_iterator<int>(std::cout," "));
 
        std::cout<<"\n\n";
        std::copy(a1.begin(), a1.end(), std::ostream_iterator<int>(std::cout," "));
        std::cout<<"\n\n";
        std::copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout," "));
 
    }
    std::cout<<"\n\n";
    return 0;
}
Добавлено через 16 минут
copy/move_and_swap можно сделать как-нибудь так к примеру. Ну это так, изврата ради.

C++
1
2
3
4
5
6
7
8
    template<typename Internal>
    void internal_swap(Internal&& rhs)
    {
       std::swap(m_size, rhs.m_size);
       std::shared_ptr<T> array = m_array;
       m_array = std::forward<std::shared_ptr<T>>(rhs.m_array);
       rhs.m_array = array;
    }
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    Array& operator=(const Array& obj)
    {
        std::cout<<"Array& operator=(const Array& obj)\n";
        if (this == &obj)
            return *this;
        Array ar(obj);
        internal_swap(ar);
        return *this;
    }
 
    Array& operator=(Array&& obj)
    {
        std::cout<<"Array& operator=(Array&& obj)\n";
        internal_swap(std::forward<Array>(obj));
        obj.m_size = 0;
        return *this;
    }
gray_fox
What a waste!
1253 / 1136 / 54
Регистрация: 21.04.2012
Сообщений: 2,359
Завершенные тесты: 3
25.12.2012, 18:21     shared_ptr и реализация семантики переноса #7
Как вариант, не особо красиво конечно)
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
#include <iostream>
#include <memory>
#include <utility>
#include <algorithm>
#include <iterator>
#include <type_traits>
#include <initializer_list>
 
 
template<typename T>
class array {
   
public:
   typedef array           self_type;
   typedef T               value_type;
   typedef T *             pointer;
   typedef T const*        const_pointer;
   typedef T &             reference;
   typedef T const&        const_reference;
   typedef std::size_t     size_type;
   typedef std::ptrdiff_t  difference_type;
   typedef const_pointer   iterator;
   typedef const_pointer   const_iterator;
   
   
   const_iterator begin() const {
      return arrayPtr.get();
   }
   
   const_iterator end() const {
      return arrayPtr.get() + arraySize;
   }
   
   
   const_reference operator [](size_type const idx) const {
      return arrayPtr[idx];
   }
   
   
   size_type size() const {
      return arraySize;
   }
   
   
   void swap(self_type & other) {
      std::swap(arrayPtr,  other.arrayPtr);
      std::swap(arraySize, other.ArraySize);
   }
   
   
   explicit array(size_type const s = 0, const_reference v = T())
         : arrayPtr(new T[s], std::default_delete<T[]>())
         , arraySize(s) {
      std::fill(&*arrayPtr, &*arrayPtr + arraySize, v);      
   }
         
   template<typename Iterator>
   array(Iterator const first, Iterator const last)
         : arraySize(std::distance(first, last)) {
      arrayPtr.reset(new T[arraySize], std::default_delete<T[]>());
      std::copy(first, last, &*arrayPtr);
   }
   
   template<
         typename S
       , typename = typename std::enable_if<std::is_convertible<S, T>::value>::type
   >
   array(std::initializer_list<S> list)
         : array(std::begin(list), std::end(list)) {}
   
   array(self_type const& other)
         : arrayPtr(other.arrayPtr)
         , arraySize(other.arraySize) {}
   
   template<
         typename S
       , typename = typename std::enable_if<std::is_convertible<S, T>::value>::type
   >
   array(array<S> const& other)
         : array(other.begin(), other.end()) {}
      
   array(self_type && other)
         : arrayPtr(std::move(other.arrayPtr))
         , arraySize(other.arraySize) {}
           
   
   array & operator =(array const&) = delete;
   array & operator =(array &&)     = delete;
            
  
private:
   template<typename S>
   friend class array;
   
   template<typename S, typename L>
   array<typename std::common_type<S, L>::type>
   friend operator +(array<S> const& lhs, array<L> const& rhs);
   
 
   std::shared_ptr<T>   arrayPtr;
   size_type            arraySize;
};
 
 
template<typename T, typename S>
array<typename std::common_type<T, S>::type>
operator +(array<T> const& lhs, array<S> const& rhs) {
   using result_type = typename std::common_type<T, S>::type;
   
   array<result_type> result(std::max(lhs.size(), rhs.size()));
   
   if (lhs.size() < rhs.size()) {
      std::copy(rhs.begin(), rhs.end(), &*result.arrayPtr);
      std::transform(lhs.begin(), lhs.end(), rhs.begin(), &*result.arrayPtr, std::plus<result_type>());
   } else {
      std::copy(lhs.begin(), lhs.end(), &*result.arrayPtr);
      std::transform(rhs.begin(), rhs.end(), lhs.begin(), &*result.arrayPtr, std::plus<result_type>());
   }
   
   return result;
}
 
 
int main() {
   array<int>     a1 = {1, 2, 3, 4, 5};
   array<double>  a2 = {1.23, 432., 5.66, 5.56};
   array<int>     b1(a1);
   array<double>  b2(a2);
   array<float>   b3(a1);
   
   auto r1 = a1 + b1;
   std::copy(std::begin(r1), std::end(r1), std::ostream_iterator<int>(std::cout, " "));
   std::cout << std::endl;
   
   auto r2 = a1 + a2;
   std::copy(std::begin(r2), std::end(r2), std::ostream_iterator<double>(std::cout, " "));
   std::cout << std::endl;
   
   auto r3 = b1 + b2 + b3;
   std::copy(std::begin(r3), std::end(r3), std::ostream_iterator<double>(std::cout, " "));
   std::cout << std::endl;
   
   auto r4 = std::move(r3);
   std::copy(std::begin(r4), std::end(r4), std::ostream_iterator<double>(std::cout, " "));
   std::cout << std::endl;
}
Avazart
7045 / 5222 / 259
Регистрация: 10.12.2010
Сообщений: 22,962
Записей в блоге: 17
28.12.2012, 15:24     shared_ptr и реализация семантики переноса #8
Стоит отметить, что рассмотренные мною умные указатели (кроме unique_ptr) не предназначен для владения массивами. Это связано с тем, что деструктор вызывает именно delete, а не delete[] (что требуется для массивов).
http://www.kalnitsky.org/2011/11/02/...ters-in-cpp11/
DiffEreD
1427 / 764 / 95
Регистрация: 21.06.2011
Сообщений: 1,740
Записей в блоге: 2
28.12.2012, 15:29  [ТС]     shared_ptr и реализация семантики переноса #9
Ну так default_delete для чего придумали: http://en.cppreference.com/w/cpp/memory/default_delete
Avazart
7045 / 5222 / 259
Регистрация: 10.12.2010
Сообщений: 22,962
Записей в блоге: 17
28.12.2012, 15:55     shared_ptr и реализация семантики переноса #10
20.7.1.1.1 In general [unique.ptr.dltr.general]
1 The class template default_delete serves as the default deleter (destruction policy) for the class template
unique_ptr.
2 The template parameter T of default_delete may be an incomplete type.
Разве это не только для std::unique_ptr ?

Добавлено через 10 минут
Все понял... не не только для std::unique_ptr
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.02.2017, 23:42     shared_ptr и реализация семантики переноса
Еще ссылки по теме:

Allocator и shared_ptr C++
C++ This для shared_ptr
Реализация shared_ptr C++
C++ Нюансы синтаксиса и семантики: что такое rvalue и lvalue?
Нюансы синтаксиса и семантики: ссылки, указатели и массивы в качестве аргументов функций C++

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

Или воспользуйтесь поиском по форуму:
zarko97
246 / 27 / 0
Регистрация: 11.10.2015
Сообщений: 153
26.02.2017, 23:42     shared_ptr и реализация семантики переноса #11
gray_fox, вот так ,думаю, будет надежнее
C++
1
std::fill(std::addressof(*arrayPtr), std::addressof(*arrayPtr) + arraySize, v);
Yandex
Объявления
26.02.2017, 23:42     shared_ptr и реализация семантики переноса
Ответ Создать тему
Опции темы

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