class MemoryStack
{
public:
MemoryStack(unsigned size)
{
mSize=size;
mTop=0;
mBuffer = new(std::nothrow) char [size];
}
char* allocate(unsigned size)
{
if (mTop + size > mSize)
return nullptr;
char* out = mBuffer+mTop;
mTop+=size;
return out;
}
private:
char* mBuffer;
unsigned mTop;
unsigned mSize;
};
int main ()
{
MemoryStack stack(1024);
int testval = 6;
int* ptr = (int*)stack.allocate(sizeof(int));
*ptr = testval;
std::cout<<*ptr;
}
现在,这个工作,然后打印出6.然而,当我尝试类似的东西时:
int main ()
{
MemoryStack stack(1024);
std::string str = "HELLO :p";
std::string* strptr = (std::string*)stack.allocate(sizeof(std::string));
*strptr = str ;
std::cout<<*strptr;
}
...这给了我一个Bad Ptr问题和一个分段错误,导致程序崩溃。谁能解释为什么会这样?这可能是因为某些运算符=重载?有没有办法安全地处理这个?谢谢!
修改 以下代码是我收到的帮助之后的最新实现 - 它没有经过全面测试,但似乎按预期工作。如果发现任何错误,我会自然地修改它,但是为了帮助任何感兴趣的人,这里是^ _ ^如果你愿意,可以随意使用它,虽然它几乎不是计算机科学的顶峰。
class MemoryStack;
/**Serves as a bookmark for the memory stack in order to allow to clear only part of the memory.*/
class MemoryBookmark
{
private:
/**Private constructor may only be called by the memory stack object.*/
MemoryBookmark(unsigned value)
{
mBookmark = value;
}
unsigned mBookmark;
public:
friend class MemoryStack;
/**Returns the index of the position that will be the new stack top pointer.*/
decltype(mBookmark) getValue() const
{
return mBookmark;
}
};
/**Acts as a basic memory stack to help reduce allocation costs, as well as add to the fun! Use with care, as destructors must be called manually.*/
class MemoryStack
{
private:
char* mBuffer;
size_t mTop;
size_t mCapacity;
size_t mAlignment;
public:
/**Initialises the class, reserving _capacity_ bytes for use. It can not be resized for efficiency purposes.*/
MemoryStack(unsigned capacity)
{
mCapacity = capacity;
mTop = 0;
mBuffer = new(std::nothrow) char[capacity];
mAlignment = 4;
}
/**Frees the memory, invalidating all internal memory. Doesn't call destructors.*/
~MemoryStack()
{
if (mBuffer)
delete[] mBuffer;
}
/**Creates an instance of the given type with Args if possible, using aligned internal memory.*/
template <typename T, typename... Args>
void create(T*& ptr, Args&&... args)
{
ptr = (T*)allocate(sizeof(T));
if (!ptr)
return;
else
new (ptr)T(std::forward<Args>(args)...);
}
/**Calls the destructor of the pointer. Must be used if destruction important.*/
template<typename T>
void destroy(T* ptr)
{
ptr->~T();
}
/**Allocates a piece of memory for use.*/
void* allocate(size_t amount)
{
size_t bt = (size_t)(mBuffer + mTop);
size_t alignoffset = mAlignment - (bt & (mAlignment - 1));
alignoffset = alignoffset == mAlignment ? 0 : alignoffset;
size_t size = amount + alignoffset;
if (size + mTop > mCapacity)
return nullptr;
else
{
mTop += size;
return (void*)(bt + alignoffset);
}
}
/**Returns the amount of memory used.*/
size_t size() const
{
return mTop;
}
/**Returns the size of the memory reserved for use.*/
size_t capacity() const
{
return mCapacity;
}
/**Returns the number of bytes remaining for allocation.*/
size_t remaining() const
{
return mCapacity - mTop;
}
/**Checks whether the internal memory was allocated successfully.*/
bool isValid() const
{
return mBuffer != nullptr;
}
/**Creates a 'bookmark' which can be used to clear the stack until a given point.*/
MemoryBookmark createBookmark() const
{
return MemoryBookmark(mTop);
}
/**Resets the stack. All data inside may now be overwritten. Doesn't call destructors.*/
void reset()
{
mTop = 0;
}
/**Resets the stack up to a given bookmark. Again, no destructors called!*/
void resetToBookmark(const MemoryBookmark bookmark)
{
mTop = bookmark.getValue();
}
/**Sets the alignment of the reservations in memory.*/
void setAlignment(size_t alignment)
{
mAlignment = alignment;
}
/**Returns the currently used alignment.*/
decltype(mAlignment) getAlignment() const
{
return mAlignment;
}
};
/**Test class.*/
class Test
{
public:
Test(int val)
{
v = val;
std::cerr << "Constructor\n";
}
~Test()
{
std::cerr << "Destructor";
}
int v;
};
/**Test it! XD*/
int main()
{
using namespace std;
{
MemoryStack stack(4096);
Test* test=nullptr;
int* i1, *i2;
char* c1, *c2;
stack.create(test,3);
stack.create(i1, 2);
stack.create(c1, 'a');
stack.create(i2, 3);
stack.create(c2, 'm');
stack.destroy(test);
stack.reset();
}
cin.get();
}
答案 0 :(得分:1)
未初始化的内存区域不是std::string
。你必须在一个区域中构建一个对象,其位置为new,如下所示:
std::string *strptr = (std::string*) stack.allocate(sizeof(std::string));
new (strptr) std::string;
值得考虑在中心位置执行此操作,例如MemoryStack
中的成员函数模板。
修改强>
我之前忘记提到这一点,这很遗憾,因为血腥重要:
如果使用placement new构造对象,则还必须手动对其进行破坏。他们不会自己做,因为他们没有自动存储持续时间,你不能使用delete
,因为内存没有分配new
。语法非常简单:
strptr->~string();
将这两部分作为MemoryStack
的一部分是个好主意,例如:{/ p>
class MemoryStack {
...
template<typename T, typename... Args>
T *create(Args&&... args) {
T *ptr = allocate(sizeof(T));
try {
new(ptr) T(std::forward<Args>(args)...);
} catch(...) {
deallocate(ptr);
throw;
}
return ptr;
}
template<typename T>
void destroy(T *ptr) {
ptr->~T();
deallocate(ptr);
}
...
};
稍后写
std::string *strptr = stack.create<std::string>("foo");
...
stack.destroy(strptr);
左右。专业提示:为自己构建一个删除器,您可以将其与std::unique_ptr
和std::shared_ptr
结合使用,以简化异常安全。
答案 1 :(得分:0)
您正在尝试分配std :: string的大小 std :: string * strptr =(std :: string *)stack.allocate(sizeof(std :: string));
你可能意味着什么 std :: string * strptr =(std :: string *)stack.allocate(str.size()));Wintermute是一个不错的主意,但它可能不会做你想要的 一个。你的分配函数将返回nullptr 湾“new”将分配一个新的内存区域,而不是在你的“堆”
中可能不会崩溃......
Draknghar :(我要年轻时添加评论) 改变主意。它会工作。但是你没有设置mTop ...... 这样做似乎有些不对劲。你已经拥有阵列并试图在其中分配新内存?为什么?只需将你的字符串复制到其中,然后设置mTop。