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

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

Войти
Регистрация
Восстановить пароль
 
 
kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
#1

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

08.06.2014, 23:07. Просмотров 966. Ответов 36
Метки нет (Все метки)

Добрый вечер всем.

Возник вопрос.
Я читал Страуструпа и на одной из его глав, есть упражнение по созданию класса-контейнера, в котором также есть контейнеры (например 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 из строки, а всю строку, которая располагается по этому адресу указателя?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.06.2014, 23:07
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как достать объект-контейнер, а не его элемент (C++):

STL. Создать объект-контейнер stack и заполнить его данными типа double - C++
Задание: 1. Создать объект-контейнер и заполнить его данными, тип которых определяется вариантом задания. 2. Посмотреть контейнер. 3....

Может ли объект-член, или объект-элемент достучаться к содержащему его? - C++
Предположим, class A { ... }; class B { .... A a; ... };

Как достать указатель на объект из контейнера set - C++
Имеется вот такой код #include &quot;stdafx.h&quot; #include &lt;string&gt; #include &lt;iostream&gt; #include &lt;fstream&gt; #include &lt;set&gt; #include...

Контейнер map / свои стрктуры / вствить и достать. - C++
Добрый день. пытаюсь засунуть в контейнер свой тип и не получается ... Код примернно такой typedef struct { int q; short...

Работа со стеком (как достать элемент из стека?) - C++
#include &lt;iostream&gt; #include &lt;stack&gt; int main() { std::stack&lt;int&gt; a; a.push(1);

Достать нужный объект из контейнера - C++
Возник вопрос, отчасти я сам решил(получил нужный результат), но очень коряво. Мне нужно достать нужный объект из контейнера на...

36
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
09.06.2014, 00:29 #16
Цитата Сообщение от kordax Посмотреть сообщение
задание именно в том, чтобы обойтись без new
А в задании сказано, что контейнер может содержать и string-и?
0
kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
09.06.2014, 00:32  [ТС] #17
А в задании сказано, что контейнер может содержать и string-и?
Да, контейнер по-сути почти vector и содержит string.
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
09.06.2014, 00:42 #18
Я так понимаю, что n - это количестов объектов, под которые нужно выделить память? Тогда:
C++
1
2
3
4
5
6
7
T* allocat<T>::allocate(int n)
{
    if (n == 0) return NULL;
    T* p;
    p = (T*) malloc(n * sizeof(T));
    return p;
}
А потом думайте, как эту память объектами string заполнить.

Добавлено через 4 минуты
Цитата Сообщение от alsav22 Посмотреть сообщение
Я так понимаю, что n - это количестов объектов, под которые нужно выделить память?
Это так? Что в качестве значения параметра передаётся? Количество объектов или размер памяти?
1
kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
09.06.2014, 01:23  [ТС] #19
Да, всё верно.
N это количество объектов, для которох мне нужно выделить память.
Т* allocate (int n) ; // выделяет память для п объектов типа Т
Добавлено через 29 минут
Да уж, заполнить память объектами string оказалось самым сложным в этой теме.
Похоже над этим придётся ещё недели 3 посидеть.
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
09.06.2014, 02:22 #20
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
    T* allocat<T>::allocate(int n)
    {
        if (n == 0) return NULL;
        T* p;
        p = (T*) malloc(n * sizeof(T));
        for (int i = 0; i < n; ++i)
        {
            T obj;
            memcpy(p + i, &obj, sizeof(T));
        }
        
        return p;
    }
1
kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
12.06.2014, 16:43  [ТС] #21
Нашёл сегодня время наконец-таки разобраться с этой темой.
alsav22 очень сильно помог, его метод действительно сработал.
Наконец-таки, я смог создать именно объект и вернуть указатель.

Всё работает, спасибо за помощь.
Если кто столкнётся с этой проблемой, то последний вариант позволяет сделать всё без оператора new.
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
12.06.2014, 16:59 #22
Цитата Сообщение от kordax Посмотреть сообщение
Всё работает, спасибо за помощь.
Если кто столкнётся с этой проблемой, то последний вариант позволяет сделать всё без оператора new.
Это нехороший способ, с кривизной. Может работать, может нет (зависит от компилятора, режима сборки и пр.) Без new (какого-либо из) я правильных способов не знаю.
0
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 нулевым элементом, чтобы при операции присваивания не вылетал эксепшн.
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 00:21 #24
Мало кода, чтобы рассуждать.
0
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 вылетает при попытки присваивания несуществующего значения.
0
alsav22
5421 / 4816 / 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
}
0
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;
}
Работает без проблем.

Можете подсказать, почему так? Не из-за того, что указатель не встаёт на этот объект?
0
alsav22
5421 / 4816 / 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().
0
kordax
4 / 4 / 1
Регистрация: 08.06.2014
Сообщений: 89
15.06.2014, 17:17  [ТС] #29
Придётся возвращать значение или писать копии в выделенную память?
Просто в страуструпе приведён пример и мне нужно реализовать именно так.
0
alsav22
5421 / 4816 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
15.06.2014, 17:20 #30
По этому поводу я уже написал:
Цитата Сообщение от alsav22 Посмотреть сообщение
Без new (какого-либо из) я правильных способов не знаю.
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.06.2014, 17:20
Привет! Вот еще темы с ответами:

Как отсортирвоать контейнер, если его тип определяется по ходу выполнения программы? (динамическая идентификация типов) - C++
собсно #include &lt;windows.h&gt; #include &lt;stdio.h&gt; #include &lt;vector&gt; #include &lt;list&gt; #include &lt;algorithm&gt; #include &lt;cxxabi.h&gt; ...

Описать класс "Контейнер" как объект, предназначенный для транспортировки классов "Строительных блоков" - C++
1. Опишите класс &quot;Строительный блок&quot;, описывающий габариты и массу блока прямоугольной формы. Данные класса: Габариты, масса. Методы...

Если объект константный, означает ли это, что ни один его член-элемент или член-метод не изменится? - C++
Назрел такой вопрос: Если объект константный это означает, что ни один его член-элемент или член-метод не изменится или только некоторые из...

Задача по STL (Создать объект-контейнер, очередь с приоритетом, заполнить ее данными, тип char) - C++
Помогите,пожалуйста, заранее спасибо)) Вот задание: 1. Создать объект-контейнер, очередь с приоритетом, заполнить ее данными, тип...


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

Или воспользуйтесь поиском по форуму:
30
Yandex
Объявления
15.06.2014, 17:20
Ответ Создать тему
Опции темы

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