[edit] Вне этого метода get (см. ниже), я хотел бы получить double * result;
указатель double * result;
а затем вызовите метод get, т.е.
// Pull results out
int story = 3;
double * data;
int len;
m_Scene->GetSectionStoryGrid_m(story, data, len);
с этим сказал, я хочу метод get, который просто устанавливает результат (* & data) по ссылке и не динамически выделяет память.
Результаты, которые я ищу, уже существуют в памяти, но они находятся внутри C-структур и не находятся в одном непрерывном блоке памяти. Fyi, & len - это просто длина массива. Я хочу один большой массив, который содержит все результаты.
Поскольку фактические результаты, которые я ищу, хранятся внутри собственного указателя C-struct story_ptr->int_hv[i].ab.center.x;
, Как мне избежать динамического выделения памяти, как я делаю выше? Id хотел бы указать данные * на результаты, но я просто не знаю, как это сделать. Вероятно, это что-то простое, я пропускаю... Код ниже.
Возможно ли это? Из того, что я читал, это не так, но, как следует из моего имени пользователя, я не разработчик программного обеспечения. Спасибо всем, кто ответил до сих пор, кстати!
Вот фрагмент кода:
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
std::stringstream LogMessage;
if (!ValidateStoryNumber(story_number))
{
data = NULL;
len = -1;
}
else
{
// Check to see if we already retrieved this result
if ( m_dStoryNum_To_GridMap_m.find(story_number) == m_dStoryNum_To_GridMap_m.end() )
{
data = new double[GetSectionNumInternalHazardVolumes()*3];
len = GetSectionNumInternalHazardVolumes()*3;
Story * story_ptr = m_StoriesInSection.at(story_number-1);
int counter = 0; // counts the current int hv number we are on
for ( int i = 0; i < GetSectionNumInternalHazardVolumes() && story_ptr->int_hv != NULL; i++ )
{
data[0 + counter] = story_ptr->int_hv[i].ab.center.x;
data[1 + counter] = story_ptr->int_hv[i].ab.center.y;
data[2 + counter] = story_ptr->int_hv[i].ab.center.z;
m_dStoryNum_To_GridMap_m.insert( std::pair<int, double*>(story_number,data));
counter += 3;
}
}
else
{
data = m_dStoryNum_To_GridMap_m.find(story_number)->second;
len = GetSectionNumInternalHazardVolumes()*3;
}
}
}
Подумайте о возврате пользовательского класса accessor вместо "double * & data". В зависимости от ваших потребностей класс будет выглядеть примерно так:
class StoryGrid {
public:
StoryGrid(int story_index):m_storyIndex(story_index) {
m_storyPtr = m_StoriesInSection.at(story_index-1);
}
inline int length() { return GetSectionNumInternalHazardVolumes()*3; }
double &operator[](int index) {
int i = index / 3;
int axis = index % 3;
switch(axis){
case 0: return m_storyPtr->int_hv[i].ab.center.x;
case 1: return m_storyPtr->int_hv[i].ab.center.y;
case 2: return m_storyPtr->int_hv[i].ab.center.z;
}
}
};
Извините за любые проблемы с синтаксисом, но вы получите эту идею. Верните ссылку на это и запишите это на своей карте. Если все сделано правильно, карта с последующим управлением всем необходимым динамическим распределением.
Таким образом, вы хотите, чтобы выделенный массив переместился "вниз" в стек вызовов. Вы можете достичь этого, выделив его в кучу, используя динамическое распределение. Или создание static
переменной, поскольку жизненный цикл static
переменных не контролируется стеком вызовов.
void GetSectionStoryGrid_m( int story_number, double *&data, int &len )
{
static g_data[DATA_SIZE];
data = g_data;
// continues ...
Если вы хотите "избежать любого выделения", решение от @Speed8ump - ваш первый выбор! Но тогда у вас не будет вашего double * result;
больше. Вы будете превращать свое "автономное" решение (сначала вычисляет весь массив, а затем использовать массив в другом месте) в "онлайн-решение" (вычисляет значения по мере необходимости). Это хороший рефакторинг, чтобы избежать выделения памяти.
Этот ответ на этот вопрос зависит от времени жизни double
к double
вы хотите указать указатели. Рассматривать:
// "pointless" because it takes no input and throws away all its work
void pointless_function()
{
double foo = 3.14159;
int j = 0;
for (int i = 0; i < 10; ++i) {
j += i;
}
}
foo
существует и имеет значение внутри pointless_function
, но перестает существовать, как только функция завершается. Даже если вы могли бы получить указатель на него, этот указатель был бы бесполезен за пределами pointless_function
. Это был бы висячий указатель, и разыменование его вызывало бы неопределенное поведение.
С другой стороны, вы правы, что если у вас есть данные в памяти (и вы можете гарантировать, что он будет жить достаточно долго для того, что вы хотите с ним делать), может быть хорошей идеей получить указатели на эти данные, а не платить стоимость его копирования. Однако основной способ передачи данных для функции, создающей ее, - это вызов new
, new[]
или malloc
. Вы действительно не можете уйти от этого.
Глядя на код, который вы опубликовали, я не вижу, как вы можете избежать new[]
-ing удвоений при создании story
. Но затем вы можете получить указатели на эти двойники позже, не требуя повторного вызова new
или new[]
.
Следует отметить, что указатели на данные могут использоваться для изменения исходных данных. Часто это может привести к ошибкам, затрудняющим отслеживание. Таким образом, есть время, когда лучше заплатить цену за копирование данных (которые вы тогда можете гасить, как хотите), или получить указатель на константу (в данном случае const double*
или double const*
, они эквивалентны: указатель-на-const даст вам ошибку компилятора, если вы попытаетесь изменить отображаемые данные). Фактически, так часто бывает, что совет должен быть инвертирован: "Есть несколько раз, когда вы не хотите копировать или получать указатель на константу, в этих случаях вы должны быть очень осторожны".
static
в области действия функции.
const double*
и double const*
не эквивалентны!
new
/delete
и высокого риска утечек памяти и висячих указателей) ? Первое не обязательно должно сопровождаться вторым.