Одноэлементный класс для перемещения кучи в стек

Я написал некий класс, который перемещает выделенный в кучу материал в стек (надеюсь :)). Этот вызов является одноэлементным, потому что только этот класс должен отвечать за хранение и управление частью стека. Мой вопрос: правильный ли мой код? Код правильный в смысле программирования (без ошибок компиляции, без ошибок памяти и утечек (проверено valgrind)). Но действительно ли код перемещает кучу в стек? Вот код:

stack.hpp:

class CStack{
public:
  void* getAlloc(long);
  static CStack* Instance();

private:
  static bool _data[5*sizeof(double)];
  static CStack* m_pInstance;

  CStack(){};
  CStack(const CStack&);
  CStack& operator=(const CStack&);
};

stack.cpp:

#include <iostream>
#include "stack.hpp"

CStack* CStack::m_pInstance = 0;

bool CStack::_data[ 5*sizeof(double) ] = { 1 };

CStack* CStack::Instance(){
  if (!m_pInstance)
    m_pInstance = new CStack;
  return m_pInstance;
}

void* CStack::getAlloc(long size){
  std::cout << "  CStack::getAlloc, " << _data << std::endl;
  _pos+=size;
  return &_data[0];
}

store.hpp

class CStore{
public:
  CStore();
  double* myAddr();
  void toStack();
  void out();
  ~CStore();
private:
  double *_data;
  bool _stack;
};

store.cpp:

#include <iostream>
#include <cstring>
#include "store.hpp"
#include "stack.hpp"

CStore::CStore(){
  _data = new double[4];
  _data[0] = 0.1;
  _data[1] = 1.1;
  _data[2] = 2.1;
  _data[3] = 3.1;
  _stack = 0;
}

double* CStore::myAddr(){ return _data; }

void CStore::toStack(){
  double *tmp;

  tmp = (double*)CStack::Instance() -> getAlloc(4*sizeof(double));

  memcpy(tmp, _data, 4*sizeof(double));
  delete [] _data;
  _data = tmp;
  _stack = 1;
}

CStore::~CStore(){
  if (!_stack)
    delete [] _data;
}

void CStore::out(){
  std::cout << _data[0] << " " << _data[1] << " " << _data[2] << " " << _data[3] << std::endl;
}

main.cpp:

#include <iostream>

#include "stack.hpp"
#include "store.hpp"

using namespace std;

int main(){
  CStack::Instance();
  CStore a;
  double stack;

  cout << &stack << endl;
  cout << "Adresa a " << a.myAddr() << endl;
  a.out();

  a.toStack();
  cout << "Adresa a " << a.myAddr() << endl;
  a.out();

  return 0;
}

person TauWich    schedule 26.11.2011    source источник
comment
Поскольку внутри вы используете m_pInstance в куче, то наверняка другие части также выделяются в куче?   -  person Jim Jeffries    schedule 26.11.2011
comment
CStack* CStack::Instance(){ if (!m_pInstance) m_pInstance = new CStack; return m_pInstance;} означает, что ваш объект находится в куче (см. Не-размещение new?).   -  person dmckee --- ex-moderator kitten    schedule 26.11.2011
comment
›› Но действительно ли код перемещает кучу в стек? Он перемещает материал в коллекцию, называемую стеком, но сама коллекция находится в куче, поэтому нет.   -  person Steve Wellens    schedule 26.11.2011
comment
Я этого боялся, потому что записанные адреса были далеко от адреса стека var. Я надеюсь, что смогу решить эту проблему, объявив CStack :: _ data static, я ошибался. Есть ли возможность иметь одноэлементный класс, который управляет стеком программ?   -  person TauWich    schedule 26.11.2011
comment
Насколько хорошо вы понимаете разницу между кучей и стеком? Знаете ли вы, что стек - это ограниченный ресурс в некоторых системах, и что использование слишком большого количества ресурсов может вызвать у вас проблемы? Вы знаете, относится ли ваша платформа к их числу? Сколько памяти вы собираетесь использовать таким образом? И, прежде всего, почему вы хотите это сделать - мы не сможем дать хороший совет, если не узнаем причину этого желания.   -  person dmckee --- ex-moderator kitten    schedule 26.11.2011
comment
В любом случае спасибо всем за быстрые ответы, я очень ценю это. Относительно последнего комментария dmckee: возможно, я неправильно различаю кучу и стек. Я знаю, что стек - дефицитный ресурс, но я буду использовать программу самостоятельно и переносить ее между mingw и linux (я мог бы установить неограниченный стек). Я собираюсь сохранить в стеке много памяти. О последнем замечании: я написал приложение CFD, основанное на хранении переменных в стеке, что было неудобно программисту, чем я переписал его, чтобы использовать кучу, из-за чего приложение работало в два раза медленнее. Я имею в виду, что приведенный выше подход - хороший гибрид. заранее спасибо   -  person TauWich    schedule 26.11.2011
comment
Использование кучи per se не должно быть намного медленнее, чем использование стека. Возможно, вам лучше поискать почему ваша реализация кучи намного медленнее. Очевидным решением для хранения некоторого объекта в мешке является выделение большого буфера сразу после запуска и перегрузка new на объектах-кандидатах для вызова настраиваемого распределителя, который использует этот буфер, но это много работы и чревато опасностями, и это не так. решить проблему, необходимую для того, чтобы знать, сколько памяти нам нужно во время компиляции.   -  person dmckee --- ex-moderator kitten    schedule 26.11.2011
comment
Если я вас правильно понял, склоняюсь к аналогичному решению. Для хранения некоторого большого объекта или объектов (но данных CStack :: _) в стеке, который мог бы получить доступ только к вышеупомянутому одноэлементному классу CStack и мог бы выполнять все необходимое управление памятью. Вы правы, что приложение, использующее аллоки кучи, не должно быть таким медленным, в любом случае стек хоть немного быстрее. Возможно, я создам новую ветку.   -  person TauWich    schedule 26.11.2011
comment
alloca () можете ли вы складывать память, но пока я бы не стал об этом беспокоиться.   -  person Michael Dorgan    schedule 29.11.2011


Ответы (1)


Нет, это полная чушь.

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

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

Во-вторых, если вам нужно использовать приведение в C ++, например:

tmp = (double*)CStack::Instance() -> getAlloc(4*sizeof(double));

Вы явно ошиблись. Пока не используйте void* в C ++. Вы можете использовать его позже, когда вам станет лучше, а не сейчас.

Главный вопрос: ПОЧЕМУ вы не хотите переносить переменные в стек? если вы просто хотите распределять динамически, зачем по-прежнему ограничивать его областью действия, используйте умные указатели, такие как std :: auto_ptr.

если вы хотите создать стек и использовать его для хранения ваших двойников, вы можете написать:

#include <vector>

int foo()
{
  std::vector<double> stack;

  // push values on the stack
  stack.push_back(1.1);
  stack.push_back(1.2);
  stack.push_back(1.3);

  // remove values from the stack
  stack.pop_back();
  stack.pop_back();
  stack.pop_back();
}
person Evan Dark    schedule 29.11.2011
comment
Я думаю, что ваш векторный материал сильно запутает этого человека. Это вектор с именем stack, объявлен локальным (в стеке) и используется как стек, но все значения сохраняются в куче. - person SoapBox; 29.11.2011
comment
Позже я сообщил, что CStack создается динамически в куче, следовательно, весь его контекст. Я думал, что создание CStack в стеке поможет, но его нарушающий шаблон singleton, см. stackoverflow.com/questions/8284561/. Я нашел обходной путь, который позже опубликую, чтобы подвергнуть критике. - person TauWich; 29.11.2011