повторное использование внутреннего адресного пространства с векторами, созданными внутри цикла - PullRequest
2 голосов
/ 28 января 2011

Придуманный пример ниже показывает повторяющиеся адреса, видимые внутри цикла.То же самое явление проявляется, когда я строю как с оптимизацией, так и без нее на MinGW GCC 4.5.0.Проблема, с которой я сталкиваюсь, заключается в том, что когда я создаю вектор внутри цикла, иногда кажется, что внутренний массив занимает те же адреса памяти, что и вектор, созданный на предыдущей итерации.Мой вопрос заключается в том, что вызывает это?

Вопрос относится ко мне, потому что у меня был некоторый код, который (по существу) передавал ссылку на вектор, созданный внутри цикла, в новый поток.Потоки попирали друг друга и вызывали сбой программы.Когда я изменил код для создания векторов вне цикла, программа работала нормально и показала те же результаты, что и однопоточная версия моей программы.

#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <cstdlib>
//using NULL;
#include <algorithm>
using std::for_each;
#include <tr1/functional>
using std::tr1::bind;
using std::tr1::placeholders::_1;

template<typename T>
void write_address(T const & arg){
    cout<<" "<<&arg;
}

template <typename T>
void write_container_addresses(vector<T> const & container){
    for_each(container.begin(),container.end(),
            write_address<T>);
    cout<<endl;
}

template <typename T>
void write_container_container_addresses(
        vector<vector<T> > const & container){
    for_each(container.begin(),container.end(),
            write_container_addresses<T>);
}

int main() {
    vector<vector<int> > stacked_vector(5);
    for_each(stacked_vector.begin(),stacked_vector.end(),
            bind(&vector<int>::reserve,_1,9));
    for_each(stacked_vector.begin(),stacked_vector.end(),
            bind(&vector<int>::resize,_1,5,0));

    cout<<"stacked vector addresses"<<endl;
    for (size_t i = 0;i<stacked_vector.size();i++){
        write_container_addresses<int>(stacked_vector[i]);
    }
    cout<<endl;

    cout<<"another print of stacked vector addresses"<<endl;
    write_container_container_addresses(stacked_vector);
    cout<<endl;

    vector<vector<int> > other_stacked_vector;

    cout<<"other vector addresses"<<endl;
    for (size_t i = 0;i<stacked_vector.size();i++){
        other_stacked_vector.push_back(vector<int>());
        other_stacked_vector.back().reserve(9);
        other_stacked_vector.back().resize(5,0);
        write_container_addresses<int>(other_stacked_vector[i]);
    }
    cout<<endl;

    cout<<"another write of other vector addresses"<<endl;
    write_container_container_addresses<int>(other_stacked_vector);

    return 0;
}

Вывод:

C:\workspace\test_of_pointer_vector_addresses\Debug>test_of_pointer_vector_addre
sses.exe
stacked vector addresses
 0x3e3e08 0x3e3e0c 0x3e3e10 0x3e3e14 0x3e3e18
 0x3e3e38 0x3e3e3c 0x3e3e40 0x3e3e44 0x3e3e48
 0x3e3e68 0x3e3e6c 0x3e3e70 0x3e3e74 0x3e3e78
 0x3e3e98 0x3e3e9c 0x3e3ea0 0x3e3ea4 0x3e3ea8
 0x3e3ec8 0x3e3ecc 0x3e3ed0 0x3e3ed4 0x3e3ed8

another print of stacked vector addresses
 0x3e3e08 0x3e3e0c 0x3e3e10 0x3e3e14 0x3e3e18
 0x3e3e38 0x3e3e3c 0x3e3e40 0x3e3e44 0x3e3e48
 0x3e3e68 0x3e3e6c 0x3e3e70 0x3e3e74 0x3e3e78
 0x3e3e98 0x3e3e9c 0x3e3ea0 0x3e3ea4 0x3e3ea8
 0x3e3ec8 0x3e3ecc 0x3e3ed0 0x3e3ed4 0x3e3ed8

other vector addresses
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e3f10 0x3e3f14 0x3e3f18 0x3e3f1c 0x3e3f20
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440

another write of other vector addresses
 0x3e3f40 0x3e3f44 0x3e3f48 0x3e3f4c 0x3e3f50
 0x3e3f60 0x3e3f64 0x3e3f68 0x3e3f6c 0x3e3f70
 0x3e24c8 0x3e24cc 0x3e24d0 0x3e24d4 0x3e24d8
 0x3e24e8 0x3e24ec 0x3e24f0 0x3e24f4 0x3e24f8
 0x3e2430 0x3e2434 0x3e2438 0x3e243c 0x3e2440

1 Ответ

3 голосов
/ 28 января 2011

Я вижу проблему в этом цикле:

cout<<"other vector addresses"<<endl;
for (size_t i = 0;i<stacked_vector.size();i++){
    other_stacked_vector.push_back(vector<int>());
    other_stacked_vector.back().reserve(9);
    other_stacked_vector.back().resize(5,0);
    write_container_addresses<int>(other_stacked_vector[i]);
}
cout<<endl;

вы пишете адреса после того, как каждый субвектор был добавлен в сложенный вектор.Проблема в том, что при следующей итерации и при вызове push_back() адреса, которые отображались для предыдущей итерации, могут быть недействительными.Это связано с тем, что операции push_back может потребоваться перераспределить память, что приведет к перемещению всех векторов в стеке векторов.

Более простая демонстрация заключается в следующем:

vector<int> vec;
vec.push_back(1);
int* p = &vec[0];
vec.push_back(2);
cout << *p << endl;  //ERROR: p possibly no longer valid.

Послеpush_back вызов, когда пространство не было зарезервировано в векторе, все указатели / ссылки / итераторы на внутреннюю память в векторе могут быть недействительными, потому что может потребоваться перераспределить и переместить память, чтобы добавить новый элемент и сохранить непрерывное хранилище.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...