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

Как достать объект-контейнер, а не его элемент - C++

Восстановить пароль Регистрация
 
 
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
08.06.2014, 23:07     Как достать объект-контейнер, а не его элемент #1
Добрый вечер всем.

Возник вопрос.
Я читал Страуструпа и на одной из его глав, есть упражнение по созданию класса-контейнера, в котором также есть контейнеры (например vector и string).
Суть следующая:

У меня есть Структура S и шаблон, со своим распределителем памяти.
В структуре S есть указатель val, который хранит адрес 1-го элемента.

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
template <class T, class A = allocat<T> > struct S
{
private:
    unsigned int buffer;
    unsigned int size;
    T* val;
    A alloc;
public:
    //S(T t) : val(t) { cout << "Constructor called" << endl; }
 
    S() :size(0), buffer(0), val(0) { cout << "Default constructor called" << endl; }
    S(const unsigned int sz) :size(0), buffer(0), val(0) { resize(sz); }
    ~S() { alloc.deallocate(this->val, size); cout << "Destructor called" << endl; } //val && this->val
//===========================================================
    T& operator=(T&);
    istream& operator>> (istream&);
    T& operator[](unsigned int);
    const T& operator[](const unsigned int) const;
    T& get_val();
    void set_val(const T&);
    void read_val (T&);
//===========================================================
    void reserve(const unsigned int);
    void resize(const unsigned int);
    void push_back(const T&);
//===========================================================
};
Сам класс S должен уметь хранить в себе кучу объектов, причем некоторые объекты сами являются контейнерами.
Например, есть код:

C++
1
2
    S<string> s_string(3);
    S<vector <int> > s_vectors(4);
Само собой, я перегрузил оператор индексации, чтобы я мог получать нужный мне объект из моей структуры.
Но проблема вот в чём, при обращении к индексу моего класса, оператор индексации выводит не объект-контейнер, а объект в контейнере.
Т.е. я получаю не сам вектор, а его элемент.

C++
1
2
3
4
5
6
7
template <class T, class A>
const T& S<T,A>::operator[](unsigned int i) const
{
    //if (i < 0) throw Range_error(i);
    //if (i > size) throw Range_error(i);
    return val[i];
}
Сам я новичок, подскажите пожалуйста, что можно придумать, чтобы на запрос s_strings[1], получать не 1 char из строки, а всю строку, которая располагается по этому адресу указателя?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.06.2014, 23:07     Как достать объект-контейнер, а не его элемент
Посмотрите здесь:

Контейнер map / свои стрктуры / вствить и достать. C++
C++ Как отсортирвоать контейнер, если его тип определяется по ходу выполнения программы? (динамическая идентификация типов)
C++ Как достать указатель на объект из контейнера set
C++ Работа со стеком (как достать элемент из стека?)
C++ STL. Создать объект-контейнер stack и заполнить его данными типа double
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
12.06.2014, 16:43  [ТС]     Как достать объект-контейнер, а не его элемент #21
Нашёл сегодня время наконец-таки разобраться с этой темой.
alsav22 очень сильно помог, его метод действительно сработал.
Наконец-таки, я смог создать именно объект и вернуть указатель.

Всё работает, спасибо за помощь.
Если кто столкнётся с этой проблемой, то последний вариант позволяет сделать всё без оператора new.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
12.06.2014, 16:59     Как достать объект-контейнер, а не его элемент #22
Цитата Сообщение от kordax Посмотреть сообщение
Всё работает, спасибо за помощь.
Если кто столкнётся с этой проблемой, то последний вариант позволяет сделать всё без оператора new.
Это нехороший способ, с кривизной. Может работать, может нет (зависит от компилятора, режима сборки и пр.) Без new (какого-либо из) я правильных способов не знаю.
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
14.06.2014, 19:40  [ТС]     Как достать объект-контейнер, а не его элемент #23
Подниму тему ещё разок.

Есть код:

C++
1
2
3
4
    for (int i = size; i < newalloc; ++i)
    {
        alloc.construct(&newmemory[i], val[i]); // копируем
    }
C++
1
2
3
4
5
6
template<class T>
void allocat<T>::construct(T* p, const T& v)
{
    p = new T;
    *p = v;
}
Т.е. из него понятно, что функция конструирует объект по адресу p, со значением v.
Однако возникает проблема, например:
Когда я создаю объект моего класса S: S<int> s_int(2);
Я получаю ошибку на операции *p = v;

Ошибка происходит потому, что v - null_reference.
И тут возникла проблема.
Т.к. я работаю с int,double,string,char,vector в шаблоне, то я не пойму, как я могу проверить v на пустое значение или заполнить v нулевым элементом, чтобы при операции присваивания не вылетал эксепшн.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 00:21     Как достать объект-контейнер, а не его элемент #24
Мало кода, чтобы рассуждать.
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 01:21  [ТС]     Как достать объект-контейнер, а не его элемент #25
allocator.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
#include <string.h>
 
using namespace std;
 
template<class T>
class allocat {
public:
T* allocate (int n);
void deallocate(T* p, int n);
void construct(T* p, const T& v);
void destroy(T* p);
};
 
template<class T>
T* allocat<T>::allocate(int n)
{
    if (n == 0) return NULL;
    T* p;
    p = (T*) malloc(n * sizeof(T));
    return p;
}
 
template<class T>
void allocat<T>::deallocate(T* p, int n)
{
    if (n == 0) return;
    for (int i = 0; i < n; i++)
    {
        free(p);
        p++;
    }
    return;
}
 
template<class T>
void allocat<T>::construct(T* p, const T& v)
{
    p = new T;
    *p = v; // [B]Ошибка именно на этом этапе[/B]
}
 
template<class T>
void allocat<T>::destroy(T* p)
{
    delete p;
    return;
}
templates.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
#include <string>
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <allocator.h>
 
using namespace std;
 
template <class T, class A = allocat<T> > class S
{
public:
    unsigned int buffer;
    unsigned int size;
    T* val;
    A alloc;
public:
    //S(T t) : val(t) { cout << "Constructor called" << endl; }
 
    S() :size(0), buffer(0), val(0) { cout << "Default constructor called" << endl; }
    S(const unsigned int newsize) :size(0), buffer(0), val() { resize(newsize); }
    ~S() { free(val); cout << "Destructor called" << endl; } //val && this->val выдавали разное значение??? Не ясно почему.
 
    void initialize(const unsigned int);
//===========================================================
    void operator=(const string&);
    istream& operator>> (istream&);
    T& operator[](unsigned int);
    const T& operator[](const unsigned int) const;
    T& get_val();
    void set_val(const T&);
    void read_val (T&);
//===========================================================
    void reserve(const unsigned int);
    void resize(const unsigned int);
    void push_back(const T&);
//===========================================================
 
};
 
template <class T, class A>
void S<T, A>::reserve(const unsigned int newalloc)
{
    if (newalloc <= buffer) return;
    T* newmemory = alloc.allocate(newalloc);
    //=======================================================
    for (int i = size; i < newalloc; ++i)
    {
        alloc.construct(&newmemory[i], val[i]); // копируем
    }
    if (val) for (int i = size; i < newalloc; ++i)
    {
        alloc.destroy(&val[i]); // уничтожаем
    }
    //=======================================================
    alloc.deallocate(val, buffer); // освобождаем старую память
    val = newmemory;
    buffer = newalloc;
    size = newalloc;
}
 
template <class T, class A>
void S<T,A>::resize(const unsigned int newsize)
{
    if (newsize == 0) return;
    if (newsize < 0)
    {
        int cnt = 0;
        for (int i = 0; i < size; i++)
        {
            cnt++;
            if (i > newsize) delete val;
            val++;
        }
        val == val - cnt;
        return;
    }
    reserve(newsize);
    return;
}
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <templates.h>
 
using namespace std;
 
int main()
{
    S<int> s_int(2);
    S<double> s_double(2);
    S<char> s_char(2);
    S<string> s_vec(3);
    return 0;
}
Постарался убрать всё лишнее.
Проблема возникает здесь:
C++
1
2
3
4
5
void allocat<T>::construct(T* p, const T& v)
{
    p = new T;
    *p = v; // [B]Ошибка именно на этом этапе[/B]
}
Т.е. получается так, что при вызове конструктора по умолчанию, нужно выполнить allow.construct (мне ведь нужно создать объекты string), но в итоге, v пусто и *p вылетает при попытки присваивания несуществующего значения.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 03:10     Как достать объект-контейнер, а не его элемент #26
Цитата Сообщение от kordax Посмотреть сообщение
Ошибка именно на этом этапе
Всё криво, всё не так.
C++
1
2
3
4
5
6
7
8
9
10
T* newmemory = alloc.allocate(newalloc); // выделили память под объекты через malloc()
...
alloc.construct(&newmemory[i], val[i]); // что и как передаётся первым параметром?
...
template<class T>
void allocat<T>::construct(T* p, const T& v)
{
    p = new T; // что представляет из себя первый параметр и что здесь с ним происходит?
    *p = v; // [B]Ошибка именно на этом этапе[/B]
}
Аналогичный код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void f(int* p)
{
    p = new int;
    *p = 5;
}
 
int main()
{
    int* a = new int[3];
    a[2] = 3;
    
    f(&a[2]);
    
    cout << a[2] << endl; // выведет 3
}
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 15:12  [ТС]     Как достать объект-контейнер, а не его элемент #27
Действительно, проблема при создании нового объекта.
C++
1
2
3
4
void f(int* p)
{
    *p = 5;
}
Работает без проблем.

Можете подсказать, почему так? Не из-за того, что указатель не встаёт на этот объект?
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 17:15     Как достать объект-контейнер, а не его элемент #28
Цитата Сообщение от kordax Посмотреть сообщение
Действительно, проблема при создании нового объекта.
Проблема не в этом.
C++
1
2
3
4
5
6
void f(int* p)
{
    p = new int; // меняется значение копии
    *p = 5;      // по новому адресу заносится значение
    cout << *p << endl; // выведет 5
}
В функцию указатель передаётся по значению (создаётся копия), а значит, изменение значения копии в функции, никак не повлияет на значение оригинала в main().
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 17:17  [ТС]     Как достать объект-контейнер, а не его элемент #29
Придётся возвращать значение или писать копии в выделенную память?
Просто в страуструпе приведён пример и мне нужно реализовать именно так.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 17:20     Как достать объект-контейнер, а не его элемент #30
По этому поводу я уже написал:
Цитата Сообщение от alsav22 Посмотреть сообщение
Без new (какого-либо из) я правильных способов не знаю.
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 17:37  [ТС]     Как достать объект-контейнер, а не его элемент #31
Так вроде с new, но теперь в функции создаётся копия, а мне нужно в оригинал записать.
+ ещё при создании объекта, v не имеет значение и это даёт вылет.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 17:42     Как достать объект-контейнер, а не его элемент #32
Цитата Сообщение от kordax Посмотреть сообщение
Так вроде с new,
Если с new, тогда и память выделяйте через new (в reserve()) и т.д. А это всё - извращения.
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 18:27  [ТС]     Как достать объект-контейнер, а не его элемент #33
Решил проблему переписав код.
Ошибка ещё была на этапе определения размера контейнера, я намудрил.

В итоге сделал:
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
template <class T, class A>
void S<T, A>::reserve(const unsigned int newalloc)
{
    if (newalloc <= buffer) return;
    T* newmemory = alloc.allocate(newalloc);
    //=======================================================
    for (int i = size; i < size; ++i)
    {
        alloc.construct(&newmemory[i], val[i]); // копируем
    }
    if (val) for (int i = size; i < newalloc; ++i)
    {
        alloc.destroy(&val[i]); // уничтожаем
    }
    //=======================================================
    alloc.deallocate(val, buffer); // освобождаем старую память
    val = newmemory;
    buffer = newalloc;
    //size = newalloc;
}
 
template <class T, class A>
void S<T, A>::resize(const unsigned int newsize, T obj = T())
{
reserve(newsize);
for (int i=size; i < newsize; ++i) alloc.construct(&val[i], obj);
// создаем
for (int i = newsize; i < size; ++i) alloc.destroy(&val[i]);
// унич т ожа ем
size = newsize;
}
Вроде всё работает.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 18:42     Как достать объект-контейнер, а не его элемент #34
Цитата Сообщение от kordax Посмотреть сообщение
Вроде всё работает.
Цитата Сообщение от kordax Посмотреть сообщение
for (int i=size; i < newsize; ++i) alloc.construct(&val[i], obj);
// создаем
То же самое: передача адреса по значению. Ходьба по кругу...
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 19:09  [ТС]     Как достать объект-контейнер, а не его элемент #35
То же самое: передача адреса по значению. Ходьба по кругу...
На время подключил стандартный allocator, он кажется по-другому работает, программа работает исправно.

Добавлено через 15 минут
p.s. вернул свой распределитель памяти:

C++
1
2
3
4
5
template<class T>
void allocat<T>::construct(T* p, const T& v)
{
    new (p) T(v);
}
Всё работает.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 22:30     Как достать объект-контейнер, а не его элемент #36
Цитата Сообщение от kordax Посмотреть сообщение
Всё работает.
C++
1
new (p) T(v);
Почему бы и нет? Объект создаётся в памяти при помощи new (одного из), и
значение p здесь не меняется, поэтому можно и по значению передавать:
Надеюсь знаете, что при таком new, деструктор для освобождения памяти, нужно вручную вызывать для каждого объекта?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
16.06.2014, 00:56     Как достать объект-контейнер, а не его элемент
Еще ссылки по теме:

Может ли объект-член, или объект-элемент достучаться к содержащему его? C++
Достать нужный объект из контейнера C++
Если объект константный, означает ли это, что ни один его член-элемент или член-метод не изменится? C++

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

Или воспользуйтесь поиском по форуму:
kordax
 Аватар для kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
16.06.2014, 00:56  [ТС]     Как достать объект-контейнер, а не его элемент #37
Да потом в цикле deallocate работает.
Cлучайно узнал что так можно делать.
Yandex
Объявления
16.06.2014, 00:56     Как достать объект-контейнер, а не его элемент
Ответ Создать тему
Опции темы

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