8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
1

Проверить правильность реализации умного указателя

19.10.2016, 00:57. Показов 1236. Ответов 8
Метки нет (Все метки)

?

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
template<class T>
class Auto_Ptr
{
public:
    Auto_Ptr();
    explicit Auto_Ptr(T* alloc);
    virtual ~Auto_Ptr();
    Auto_Ptr(const Auto_Ptr& arg);
 
    //возвращает (отдает) указатель, обнуляя текущий
    T* release()
    {
        T* tmp = ptr;
        ptr = nullptr;
        return tmp;
    }
    
    //возвращаем значение указателя
    T operator*() const
    {
        return *ptr;        
    }
 
    //возвращаем указатель
    T* operator->() const
    {
        if (ptr == 0)
            throw("pointer is null");
        return ptr;
    }
 
    //копирующее присваивание - запрещаем глубокое копирование (можно было не реализовывать?)
    Auto_Ptr<T>& operator=(Auto_Ptr<T>& arg)
    {
        if (ptr == arg.ptr) 
            return (*this);
        ptr = arg.release();
    }
 
private:
    T* ptr;
 
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr()
{
    ptr = new T;
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr(T* alloc)
{
    ptr = alloc;
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr(const Auto_Ptr<T>& arg)
{
    ptr = arg.release();
}
 
template<class T> Auto_Ptr<T>::~Auto_Ptr()
{
    if (ptr)
    delete ptr;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<iostream>
#include <string>
 
int main()
{
 
    setlocale(LC_ALL, "RU");
 
    Auto_Ptr <std::string> MyStr(new string);
    cout << *MyStr;
    MyStr->append("Эта стока была добавлена. Память под неё будет автоматически удалена деструктором");
    cout << *MyStr;
 
    Auto_Ptr<std::string> MyStr_2;
    cout << *MyStr_2;
    MyStr_2 = MyStr;
    cout << *MyStr_2;
    //cout << *MyStr; - тут будет ошибка (nullptr)
 
    
    _getch();
    return 0;
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.10.2016, 00:57
Ответы с готовыми решениями:

Проверить правильность преобразования указателя - преобразование из void*
Есть один абстрактний и один не абстрактний клас. В виртуальний метод передаеться указатель на...

Проверить правильность реализации метода Ньютона
Посмотрите все ли я правильно сделал вот изначальные данные: cos(x) + y = 1,5 2x - sin(y * 0,5) =...

Реализация умного указателя
Добрый вечер. Сегодня с умным указателем поиграться. Написал обгортку : #pragma once template...

Доступ к полю умного указателя
Привет. Реализовал умный указатель. Появилась проблема: Если обращаться через перегруженный...

8
Don't worry, be happy
17758 / 10526 / 2030
Регистрация: 27.09.2012
Сообщений: 26,502
Записей в блоге: 1
19.10.2016, 01:07 2
C++
1
2
3
4
5
6
7
8
9
10
11
    T operator*() const//Здесь Вы возвращаете копию, зачем?
    {//А в operator-> Вы еще на nullptr проверяете, а здесь нет...
        return *ptr;        
    }
 
    T* operator->() const
    {
        if (ptr == 0)
            throw("pointer is null");//А выбросить нормальный объект почему нельзя?
        return ptr;
    }
Зачем виртуальный деструктор?
Вы думаете когда-то это унаследовать?
Цитата Сообщение от nofx Посмотреть сообщение
//копирующее присваивание - запрещаем глубокое копирование (можно было не реализовывать?)
Раз уж используете C++11,
то реализуйте перемещение,
а копирование вообще уберите.
C++
1
2
3
4
template<class T> Auto_Ptr<T>::Auto_Ptr()
{
    ptr = new T;
};
Так указатель ведущий получается?
Но с отказом от владения?

C++
1
2
3
4
template<class T> Auto_Ptr<T>::Auto_Ptr(T* alloc)
{
    ptr = alloc;
};
ага, т.е. указатель не ведущий уже?

Надо бы определиться,
что Вы хотите от этого класса,
здесь всякого намешано.
2
16094 / 8692 / 2124
Регистрация: 30.01.2014
Сообщений: 14,985
19.10.2016, 09:44 3
Цитата Сообщение от nofx Посмотреть сообщение
C++
1
2
3
4
template<class T> Auto_Ptr<T>::Auto_Ptr(const Auto_Ptr<T>& arg) 
{ 
    ptr = arg.release(); 
}
В дополнение к вышесказанному.
Этот конструктор при использовании даст ошибку компиляции. Т.к. функция release и по объявлению и по семантике неконстантная, а ссылка на константный объект. Ошибки в примере нет только потому, что этот конструктор нигде не используется.
При этом семантическое предназначение такого конструктора - копирование, хотя по факту выполняется перемещение. В таком случае лучше, при наличии С++11, это самое перемещение и реализовать (как уже было сказано выше).
0
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
20.10.2016, 00:01  [ТС] 4
Цитата Сообщение от Croessmah Посмотреть сообщение
а копирование вообще уберите
- а его там и нет, пусть перемещает

Цитата Сообщение от Croessmah Посмотреть сообщение
Так указатель ведущий получается?
-прочитал про ведущие указатели и их семантику, я не стремился повторить их поведение.

1.Указываемые объекты должны создаваться указателями в конструкторах.
2. Деструктор указателя должен удалять указываемый объект.
3. Конструктор копий должен создавать точную копию указываемого объекта.
4. Оператор присваивания operator= должен удалять текущий указываемый объект,
находящийся слева от него, и заменять его копией указываемого объекта справа.

Цитата Сообщение от Croessmah Посмотреть сообщение
Надо бы определиться,
что Вы хотите от этого класса,
здесь всякого намешано.
Реализовать поведение auto_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
template<class T>
class Auto_Ptr
{
public:
    Auto_Ptr();
    explicit Auto_Ptr(T* alloc);
    virtual ~Auto_Ptr();
    Auto_Ptr(const Auto_Ptr& arg);
 
    //возвращает (отдает) указатель, обнуляя текущий
    T* release()
    {
        T* tmp = ptr;
        ptr = nullptr;
        return tmp;
    }
    
    //возвращаем значение указателя по ссылке
    T& operator*() const throw(std::exception)
    {
        if (ptr == 0)
            throw std::exception("pointer is null");
        return *ptr;        
    }
 
    //возвращаем указатель
    T* operator->() const throw(std::exception)
    {
        if (ptr == 0)
            throw std::exception("pointer is null");
        return ptr;
    }
 
    //копирующее присваивание - реализуем семантику перемещения.(как у auto_ptr)
    Auto_Ptr<T>& operator=(Auto_Ptr<T>& arg)
    {
        if (ptr == arg.ptr) 
            return (*this);
        ptr = arg.release();
    }
 
private:
    T* ptr;
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr()
{
    ptr = 0;
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr(T* alloc)
{
    ptr = alloc; //присвоим левому значению правое и обнулим правое...норм?
    alloc = 0;  
};
 
template<class T> Auto_Ptr<T>::Auto_Ptr(const Auto_Ptr<T>& arg)
{
    ptr = arg.release();
}
 
template<class T> Auto_Ptr<T>::~Auto_Ptr()
{
    if (ptr)
    delete ptr;
}
0
16094 / 8692 / 2124
Регистрация: 30.01.2014
Сообщений: 14,985
20.10.2016, 00:21 5
nofx, вот с таким примером собери свой код:
C++
1
2
    Auto_Ptr<int> a(new int(42));
    Auto_Ptr<int> b(a);
и с таким:
C++
1
    Auto_ptr<int> a = Auto_Ptr<int>(new int(42));
А потом еще раз перечитай #3.
У тебя в коде объявлен конструктор копирования, который пытается делать перемещение. Это не то же самое, что конструктор перемещения.

Добавлено через 13 минут
По мелочи:
Цитата Сообщение от nofx Посмотреть сообщение
C++
1
2
3
4
5
6
Auto_Ptr<T>& operator=(Auto_Ptr<T>& arg) 
{ 
    if (ptr == arg.ptr) 
        return (*this); 
    ptr = arg.release(); 
}
Здесь потерялся return.
Цитата Сообщение от nofx Посмотреть сообщение
C++
1
std::exception("pointer is null");
Конструктор с параметром у std::exception - это нестандартное расширение Visual Studio. В других компиляторах может не работать. std::runtime_error тут в помощь.
Цитата Сообщение от nofx Посмотреть сообщение
C++
1
throw(std::exception)
Спецификации исключений нынче deprecated.

Есть еще, но это после утряски вопроса с конструктором.
1
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
20.10.2016, 00:30  [ТС] 6
Да, понял.

C++
1
2
3
4
5
6
7
8
9
10
11
12
template<class T> Auto_Ptr<T>::Auto_Ptr(Auto_Ptr<T>& arg) //соnst здесь лишний
{
    ptr = arg.release();
}
        //вот так тестировал, все переносится
 
        Auto_Ptr<int> a(new int(42));
    Auto_Ptr<int> b(a);
 
    Auto_Ptr<int> a1 = Auto_Ptr<int>(new int(42));
    Auto_Ptr<int> a2 = a1;
    a1 = b; //а оператор "копирования" отрабатывает тут
Добавлено через 2 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
Спецификации исключений нынче deprecated
- не успеваеш узнавать а оно уже устарело! в stl повсюду написаны.
0
16094 / 8692 / 2124
Регистрация: 30.01.2014
Сообщений: 14,985
20.10.2016, 00:36 7
Цитата Сообщение от nofx Посмотреть сообщение
C++
1
2
//вот так тестировал, все переносится
Auto_Ptr<int> a1 = Auto_Ptr<int>(new int(42));
А здесь опять студия играет злую шутку, позволяя привязывать rvalue к неконстантной ссылке...

В общем, если цель научиться делать правильно, то сейчас надо пойти и почитать про rvalue-reference и move-semantics.
Ну или про трюки для обхода ограничений С++03, которые применялись в auto_ptr.
Если же цель заставить это работать на одном конкретном компиляторе, то можно на этом остановиться
1
8 / 8 / 5
Регистрация: 28.10.2012
Сообщений: 135
20.10.2016, 00:51  [ТС] 8
Цитата Сообщение от DrOffset Посмотреть сообщение
А здесь опять студия играет злую шутку, позволяя привязывать rvalue к неконстантной ссылке...
-правильно ли то, что для таких случаев нужно переопределять данные операции где lvalue - временный объект?
По Вашей ссылке это код в самом низу:
C++
1
2
3
4
5
6
7
8
/* special conversions with auxiliary type to enable copies and assignments
         */
        auto_ptr(auto_ptr_ref<T> rhs) throw() //rhs  - объект, видимо временный, по этому с ним ничего не делаем, сам уничтожится
         : ap(rhs.yp) {
        }
        auto_ptr& operator= (auto_ptr_ref<T> rhs) throw() {  // new
             reset(rhs.yp);
             return *this;
0
16094 / 8692 / 2124
Регистрация: 30.01.2014
Сообщений: 14,985
20.10.2016, 01:08 9
Лучший ответ Сообщение было отмечено nofx как решение

Решение

nofx, по ссылке показан костыль, который очень долго был законным способом передавать владение в таких случаях. Сейчас лучше пользоваться средствами С++11, если это возможно.
Суть костыля в том, что мы не можем использовать конструктор копирования для передачи владения в общем случае. Мы можем его использовать, если мы передаем владение от lvalue, но в случае с rvalue правила языка не позволят привязать его к неконстантной ссылке. Раз это невозможно, то необходимо было обеспечить другой путь. Этот путь заключается в неявном преобразовании auto_ptr в auto_ptr_ref (operator auto_ptr_ref) и затем вызов соответствующего конструктора (auto_ptr(auto_ptr_ref<T> rhs)). Что позволяло отнять владение у rvalue и передать его новоиспеченному объекту. С присваиванием rvalue ситуация аналогичная.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
20.10.2016, 01:08
Помогаю со студенческими работами здесь

Использование умного указателя std::weak_ptr
Есть вот такой код иерархии классов. Нужно в последнем классе list, вместо динамического массива...

Утечка при комбинации сырого и умного указателя
После выхода из блока shared_ptr вызывает деструкторы объектов, но они почему-то остаются в...

Не выводится сообшения от деструктора для умного указателя
#ifndef Shared_ptr_H #define Shared_ptr_H template&lt;class T&gt; class shared_ptr { private: ...

Передача умного указателя в функцию принимающую указатель на указатель
Итак имеется функция со следующим параметром: HRESULT __stdcall Function(SomeClass **param); ...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru