Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Последовательные контейнеры и непрерывная память

11K
19 декабря 2008 года
Babandr
76 / / 05.05.2008
Заранее извиняюсь, если вопрос уже обсуждался...

Насколько мне известно, последовательные stl-контейнеры (вектор, лист) обязаны поддерживать у пользователя иллюзию того, что они есть данные, размещенные в непрерывной памяти. Однако внутренняя их реализация якобы может этому условию не удовлетворять...
В связи с такой неоднозначностью вопрос - можно ли использовать указатели на элементы контейнеров в функциях для работы с памятью, например CopyMemory, memcmp и т.д. ?
240
19 декабря 2008 года
aks
2.5K / / 14.07.2006
list как раз не обязан ни разу. Более того это испортит в общем случае скорость произвольного добавления/удаления.
Для вектора в принципе можно было бы использовать, но не желательно. Тем более что интерфейсы STL предоставляют такую же функциональность.
87
19 декабря 2008 года
Kogrom
2.7K / / 02.02.2008
Цитата: Babandr
В связи с такой неоднозначностью вопрос - можно ли использовать указатели на элементы контейнеров в функциях для работы с памятью, например CopyMemory, memcmp и т.д. ?


Все это похоже на какое-то хакерство, что не есть хорошо. Лучше использовать алгоритмы STL, специальные конструкторы контейнеров.

11K
19 декабря 2008 года
Babandr
76 / / 05.05.2008
Значит, таки нельзя? Очень жаль...
Просто библиотека, с которой в данный момент я работаю, предоставляет кучу функций, которым надо передавать указатели на блоки памяти. А от использования stl отказываться не хотелось бы...но видимо придется.
87
19 декабря 2008 года
Kogrom
2.7K / / 02.02.2008
Цитата: Babandr
Значит, таки нельзя? Очень жаль...


Я бы наверно сделал наследник контейнера с функциями, которые динамически генерируют временный массив, с которыми бы могли работать функции той библиотеки. Есть же у строки функция c_str(). Наверно что-то подобное можно и для других контейнеров изобрести.

11K
19 декабря 2008 года
Babandr
76 / / 05.05.2008
Наследник контейнера?ээээ....больно мудро.
А насчет динамической генерации массивов...мне в программе время дорого(кучу данных надо обрабатывать), так что боюсь не пройдет така штука.
Но все равно спасибо за совет.
87
19 декабря 2008 года
Kogrom
2.7K / / 02.02.2008
Цитата: Babandr
Наследник контейнера?ээээ....больно мудро.
А насчет динамической генерации массивов...мне в программе время дорого(кучу данных надо обрабатывать), так что боюсь не пройдет така штука.


Наверно, тут больше жалко память. Возможно, времени не очень много потратится. Попробую на скорую руки изобрести (наверное, велосипед )))) )

Код:
// Наследник вектора (с шаблонами не вожусь)
struct myVector: public vector<int>
{
    int *array;
    int* GetArray()
    {
        array = new int [this->size()];
        copy(this->begin(), this->end(), array);
        return array;
    }
    void ApplyArray()
    {
        if(array)
        {
            copy(array, array + this->size(), this->begin());
            delete [] array;
        }
    }
    myVector():array(0){}
    myVector(size_t sz, int val):array(0), vector<int>(sz, val){}
    ~myVector(){if(array) delete [] array;}
};

int main()
{
    myVector v(5, 1);
    for(size_t i = 0; i < v.size(); ++i)
        cout << v << ' ';
    cout << endl;

    // Плучаем ссылку на массив
    int *p = v.GetArray();

    for(int i = 0; i < v.size(); ++i)
    {
        *(p + i) = i*2;
    }

    // удаляем массив
    v.ApplyArray();

    for(size_t i = 0; i < v.size(); ++i)
    {
        cout << v << ' ';
    }

    return 0;
}
505
21 декабря 2008 года
vAC
343 / / 28.02.2006
Класс вектора удовлетворяет такому требованию. Цитата из стандарта:
Цитата:

23.2.4 Class template vector
...
The elements of a vector are stored contiguously, meaning that if v is a vector<T, Allocator> where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().



Но использовать такие возможности без надобности не стоит - отсутствует контроль выхода за пределы вектора. Но ничего не поделаешь, если приходится использовать сторонние API с подобным вызовом.

87
22 декабря 2008 года
Kogrom
2.7K / / 02.02.2008
Цитата: vAC
Класс вектора удовлетворяет такому требованию.


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

Код:
// Наследник листа
template<class T> struct myList: public list<T>
{
    T *array;
    T* GetArray()
    {
        if(array) return array;
        array = new T [this->size()];
        copy(this->begin(), this->end(), array);
        return array;
    }
    void ApplyArray()
    {
        if(array)
        {
            copy(array, array + this->size(), this->begin());
            delete [] array;
            array = 0;
        }
    }
    myList():array(0){}
    myList(size_t sz, T val):array(0), list<T>(sz, val){}
    ~myList(){if(array) delete [] array;}
};

int main()
{
    myList<int> v(5, 1);
    for(myList<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << *it << ' ';
    cout << endl;

    // Получаем указатель на массив и работаем с ним
    for(int *p = v.GetArray() + v.size() - 1; p >= v.array; --p)
    {
        *p += 2;
    }

    // применяем и удаляем массив
    v.ApplyArray();

    for(myList<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << *it << ' ';

    return 0;
}
3
23 декабря 2008 года
Green
4.8K / / 20.01.2000
Цитата: Kogrom
Однако, не удержусь - доработаю свой код для листа.


Однако тоже не удержусь и упрощу:

Код:
int main()
{
    list<int> v(5, 1);
    for(list<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << *it << ' ';
    cout << endl;

    // Получаем указатель на массив и работаем с ним
    vector<int> array(v.begin(), v.end());
    for(int* p = &array.back(); p >= &array.front(); --p)
    {
        *p += 2;
    }

    // применяем массив
    v.clear();
    copy(array.begin(), array.end(), back_inserter(v));

    for(list<int>::iterator it = v.begin(); it != v.end(); ++it)
        cout << *it << ' ';

    return 0;
}
87
23 декабря 2008 года
Kogrom
2.7K / / 02.02.2008
Цитата: Green
Однако тоже не удержусь и упрощу


Ну, так каждый может. У меня ж там понты с наследованием контейнера :)

Если серьезно, то непонятно, почему

 
Код:
v.clear();
    copy(array.begin(), array.end(), back_inserter(v));

А не

 
Код:
copy(array.begin(), array.end(), v.begin());

В данном случае вроде размер массива всегда равен размеру листа.
3
23 декабря 2008 года
Green
4.8K / / 20.01.2000
Цитата: Kogrom
Ну, так каждый может. У меня ж там понты с наследованием контейнера :)


А вот наследоваться от контейнеров считается плохой практикой.

Цитата: Kogrom

Если серьезно, то непонятно, почему

 
Код:
v.clear();
    copy(array.begin(), array.end(), back_inserter(v));

А не

 
Код:
copy(array.begin(), array.end(), v.begin());

В данном случае вроде размер массива всегда равен размеру листа.


Ну так "во время пути, собачка могла слегка подрасти", другими словами: в процессе работы с array его размер может быть изменен в любую сторону. Конечно, можно запретить изменять размер, но я решил просто переписывать список новыми значениями.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог