Как векторный шаблон STL C ++ хранит свои объекты в реализации компилятора Visual Studio? - PullRequest
0 голосов
/ 30 июня 2009

Я расширяю отладчик Visual Studio 2003, используя autoexp.dat и DLL, чтобы улучшить способ отображения данных в окне просмотра. Основная причина, по которой я использую DLL, а не просто базовую функциональность autoexp.dat, заключается в том, что я хочу, чтобы все отображалось условно. например Я хочу иметь возможность сказать «Если имя члена не является пустой строкой, отображаемое имя, в противном случае отобразить [какой-то другой элемент]»

Я совершенно новичок в ООП и не имею никакого опыта работы с STL. Возможно, я упускаю очевидное.

У меня проблемы с отображением векторных элементов, потому что я не знаю, как получить указатель на память, в которой хранятся фактические значения.

Правильно ли я считаю, что значения хранятся в непрерывном блоке памяти? И есть ли способ получить доступ к указателю на эту память?

Спасибо!

[править:] Чтобы прояснить мою проблему (надеюсь):

В моей DLL, которая вызывается отладчиком, я использую функцию ReadDebuggeeMemory, которая создает копию памяти, используемой объектом. Он не копирует память, на которую указывает объект. Поэтому мне нужно знать фактическое значение адреса внутреннего указателя, чтобы можно было также вызывать ReadDebuggeeMemory. В настоящее время обычные методы получения векторного содержимого возвращают мусор, поскольку эта память еще не скопирована.

[обновление:]

Я получал мусор, даже когда смотрел на правильный указатель _Myfirst, потому что я создавал дополнительную копию вектора, когда мне следовало использовать указатель на вектор. Таким образом, возникает вопрос: как получить доступ к указателю на векторную память через указатель на вектор? Имеет ли это смысл?

Ответы [ 4 ]

2 голосов
/ 30 июня 2009

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

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

vector<int> v;

v.push_back(1);

int* fred = &v[0];

for (int i=0; i<100; ++i)
  v.push_back(i);

assert(fred == &v[0]); // this assert test MAY fail
2 голосов
/ 30 июня 2009

Элементы в стандартном векторе выделяются как один непрерывный фрагмент памяти.

Вы можете получить указатель на память, взяв адрес первого элемента, что можно сделать несколькими способами:

std::vector<int> vec;
/* populate vec, e.g.: vec.resize(100); */

int* arr = vec.data();   // Method 1, C++11 and beyond.
int* arr = &vec[0];      // Method 2, the common way pre-C++11.
int* arr = &vec.front(); // Method 3, alternative to method 2.

Однако, если вам не нужно передать базовый массив некоторым старым интерфейсам, обычно вы можете просто использовать операторы для вектора напрямую.

Обратите внимание, что вы можете получить доступ только к vec.size() элементам возвращаемого значения. Доступ к нему - неопределенное поведение (даже если вы думаете, что для него зарезервирована емкость).

Если у вас был указатель на вектор, вы можете сделать то же самое выше, просто разыменовав:

std::vector<int>* vecptr;

int* arr = vecptr->data(); // Method 1, C++11 and beyond.
int* arr = &(*vecptr)[0];  // Method 2, the common way pre-C++11.
int* arr = &vec->front();  // Method 3, alternative to method 2.

Еще лучше, попробуйте получить ссылку на него.

О вашем решении

Вы пришли к решению:

int* vMem = vec->_Myfirst;

Единственный раз, когда это сработает, - это конкретная реализация этой конкретной версии компилятора. Это не является стандартным, поэтому не гарантируется работа между компиляторами или даже разными версиями вашего компилятора.

Может показаться, что все в порядке, если вы разрабатываете только на одной платформе и компиляторе, но лучше сделать это стандартным способом, учитывая выбор.

0 голосов
/ 05 марта 2010

Вы не смогли реализовать решения, предложенные Гманом и Родди, потому что они отвечают, казалось бы, правильно, но не имеют никакого отношения к вашей ситуации.

При разработке Addin Dll для оценки выражений (EE) для использования с autoexp.dat вы получаете один необработанный указатель на векторный объект из вашего процесса. Но Dll работает в процессе отладчика Visual Studio, поэтому единственный способ получить доступ к данным вектора через функцию ReadDebuggeeMemory.

Вы должны использовать этот необработанный указатель и ReadDebuggeeMemory () для чтения памяти, занятой объектом в процессе Debugee, в локальный буфер / объект. (локально для процесса отладчика, что означает ваш DLL). Затем получите необходимые данные из локального объекта, если он является указателем, чем вам придется снова использовать ReadDebuggeeMemory (), чтобы прочитать объект, указанный им, в другое локальное местоположение. И так далее.

Для векторов (я не сделал это сам, чтобы быть более конкретным), вы должны 1. Считать (ReadDebuggeeMemory ()) векторный объект на локальный. 2. Получить размер вектора (я предполагаю, что это не указатель данных в классе вектор) 3. Получите указатель на эту непрерывную ячейку памяти и прочитайте (ReadDebuggeeMemory ()) этот блок в локальный буфер / блок. Размер блока - sizeof (VectorType) * VectorSize в байтах. (если оно не будет непрерывным, то все будет сложнее, но идея та же). 4. Поскольку ваш вектор содержит указатели, вы должны читать (ReadDebuggeeMemory ()) каждый элемент отдельно в локальной памяти.

0 голосов
/ 30 июня 2009

Я не смог реализовать решения, предложенные Гманом и Родди , когда я перешел от наличия векторной переменной к указателю на вектор, вполне вероятно, потому что я просто слишком невежественны

Я нашел указатель, который искал, хотя: _Myfirst

Так что мой код работает, когда я использую

std::vector<int>* vec;

int *vMem = vec->_Myfirst;

Я удивлен, что у меня есть доступ к _Myfirst. Я ожидал, что это будет частный член. Но, очевидно, нет ...

...