将字节数组转换为标准数据类型
Posted
技术标签:
【中文标题】将字节数组转换为标准数据类型【英文标题】:Convert byte array into std data type 【发布时间】:2014-11-28 13:10:15 【问题描述】:嗯,你好。我正在尝试编写一个自定义堆栈内存分配器来帮助我的游戏编程,但遇到了问题。所以,假设我的分配器有一个 char* 缓冲区,我想为 int 获取一些内存:
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 问题和一个分段错误,使我的程序崩溃。谁能解释这是为什么?这可能是因为某些运算符 = 重载吗?有什么方法可以安全地处理这个问题吗?谢谢!
编辑: 以下代码是我收到帮助后的当前最终实现 - 它没有经过彻底测试,但似乎按预期工作。发现有bug我自然会修改,不过为了帮助有兴趣的朋友,这里就放上来^_^大家可以随意使用,虽然算不上计算机科学的巅峰。
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();
【问题讨论】:
只是想知道是否真的有必要自己动手。是不是有一些你可以使用的 FOSS 让你继续玩有趣的东西?有很多免费的游戏框架和内存分配器,它们是完全开发的、经过良好测试和支持的。即使你可以做得更好(没有冒犯),你愿意花时间这样做吗? 啊,你可能是对的......但我首先是学生,知道如何做这些事情感觉很好^_^另外,这会让我有更多的控制权,并允许我在需要时扩展这些结构。 【参考方案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
的一部分,例如:
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
结合使用,以简化异常安全性。
【讨论】:
天哪,谢谢!这似乎表现得很漂亮。我以前没有使用过新的展示位置,因此必须调查性能影响以及如何正确使用它。但是我现在才试了一下,确实有效! 哦,我明白了。谢谢!我接受了您的建议,并修改了我的代码以允许使用适当的析构函数。遗憾的是,我还没有完全熟悉高级 C++11 功能,所以我选择保持内存堆栈相当简单,尽管对于我的目的来说已经足够了。我将把我的最终实现放在上面的编辑中。【参考方案2】:您正在尝试分配 std::string 的大小 std::string* strptr = (std::string*)stack.allocate(sizeof(std::string));
你的意思可能是 std::string* strptr = (std::string*)stack.allocate(str.size()));
Wintermute 是一个不错的主意,但它可能无法满足您的需求 一种。您的 allocate 函数将返回 nullptr 湾。 “新”将分配一个新的内存区域,而不是在你的“堆”中
虽然可能不会崩溃...
Draknghar:(我太年轻了要添加 cmets) 改变主意。它会起作用的。但你没有设置 mTop ...... 这样做似乎有些不对劲。你已经有了你的数组并且你试图在其中分配新的内存?为什么?只需将您的字符串复制到其中,然后设置 mTop。
【讨论】:
我刚试了一下,好像还可以。我认为他们使用的新的似乎是新的安置。因此,它应该在我的内存堆栈中。不过谢谢!以上是关于将字节数组转换为标准数据类型的主要内容,如果未能解决你的问题,请参考以下文章