在C ++中用函数包装malloc
是否有一种普遍接受的安全方法?我试图做的是分配任意大小的内存块,用于保存将二进制值写入固定大小缓冲区的函数的输出(即:机器指令)。我目前使用的方法是这样的:
class voidp {
void *p;
public:
voidp (void *pp) : p (pp) {}
template<class T> operator T *() { return (T *) p; }
};
When converting C to C++, you can define malloc like this:
inline voidp
mymalloc (size_t size)
{
return malloc (size);
}
#define malloc mymalloc
在许多情况下,似乎不允许对(void*)
进行显式强制转换(至少在我的编译器中),我必须使用上面基于模板的方法。
这种做法是否安全,是否对三&#34;规则有任何影响? (即:我需要禁用或明确定义/重载的构造函数吗?)
谢谢。
参考
<http://www.scs.stanford.edu/~dm/home/papers/c++-new.html>
<https://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me>
修改
我这样做的原因是因为我尝试使用的东西可能比通过void* buffer = new char[100]
分配一个字符块更好。为了进一步说明,我正在编写一些低级代码,根据我的建议,必须用C ++编写,而不是纯C.我还需要动态内存分配方法来创建内存块堆上的16字节,32字节和64字节对齐,如下面的示例中的16字节对齐。
{
void *mem = malloc(1024+15);
void *ptr = ((uintptr_t)mem+15) & ~ (uintptr_t)0x0F;
memset_16aligned(ptr, 0, 1024);
free(mem);
}
我的应用程序实际上在块中创建一组低级机器指令,这些块必须是16/32/64字节对齐(或者它将触发CPU级错误),然后将它们传递给板载DSP芯片,它将它们作为实际指令运行,而不仅仅是输入数据。
答案 0 :(得分:2)
主题1:旧的void*
?
C ++的输入类型比C强。 这不是问题,而是一个解决方案! 编译器以这种方式拦截了许多令人讨厌的问题找出调试时间。
简单的例子。下面的代码在C中编译。当我执行时,我得到一个核心转储。
FILE *fp; // file
void *pbuff; // pointer to buffeer
pbuff = malloc(BUFSIZ);
fp=fopen("test.txt", "rw");
fread(fp, BUFSIZ, 1, pbuff); // ooops !! Did you notice ?
为什么?我倒fp和pbuff。两者都是void*
到anything*
和anything*
到void*
结构的受害者。当然,经过实验的程序员不会在标准库上犯这样的错误!但其余的是什么?
使用C ++时,这个错误的代码无法编译,因为将void*
pbuff转换为FILE*
会被识别为问题。
主题2:模板voidp是否安全?
好吧,C ++有类和继承。还有一大堆演员来强调你可以(并且仍然允许)做的奇怪的指针操作。 C ++再次简化了bug的发现。例如,reinterpret_cast<>
比受控制的static_cast<>
要做安全的事情,需要了解C ++对象模型并使用适当的工具。你的voidp()
非常聪明,但它不是OOP的合适工具。
简单的例子,首先是本地方式:
struct A { std::string name; A(std::string s) : name(s) {} };
struct B : A { int x, y; B(std::string s, int a, int b) : A{ s }, x(a), y(b) {} };
...
A a{ "Chris" };
B b{ "Tophe", 30, 40 };
A *gpa = &a;
B *gpb = &b;
gpa = gpb; // yes, works, because a B is an A and compiler knows it.
//gpb = gpa; // No ! you can't without a recast !
现在使用voidp
方法:
voidp pa(&a);
voidp pb(&b);
pb = pa; // no problem.
gpb = pa; // no problem ! Not even a cast to draw attention on potential issue !
所以你看, 它相当不安全! 它确实隐藏了令人讨厌的错误!
主题3:malloc()
是否优于new
?
谦虚地,malloc()
您可以轻松创建任何内容。而且创建错误大小的东西也很容易....使用new
,你也可以做一些奇怪的事情,但是做基本错误会更困难。
new
可以调用对象构造函数。使用malloc()
,您需要执行额外的步骤。
然后,当您malloc()
时,您拥有free()
。 malloc()
/ free()
非常适合C语言中的被动数据结构。但是在C ++中,当你想要正确删除一个对象时,你必须去掉它。所以delete
更合适。
<强>结论强>
我感兴趣地阅读了您的参考文献。确实,new
有局限性。
但我不同意文章的结论。而不是避免new
并切换回malloc()
(再次:它非常适合C代码,但不是最适合C ++),这将是研究标准库的更好方法,例如使用shared_ptr<>
和其他智能指针。这些对于避免内存泄漏要好得多,而不是重写一个自己的malloc版本......
<强> 修改 强>
您的具体用途也可以在C ++中完成
char buffer[1024 + 15]; // allocation on stack, or char *mem = new char[1024+15]
char *ptr = reinterpret_cast<char*>(((uintptr_t)&buffer + 15) & ~(uintptr_t)0x0F); // Yes
std::fill_n(ptr, 0, 1024); // is memset_16aligned() really portable ?
// nothing if on stack // or delete[] mem if new was used
还存在函数std::align()
,它为ptr执行计算。
并且有一个placement-new可以在固定地址上分配C ++对象,例如:
char* p = new(ptr)char[1024]; // of course you shouldn't delete this one
答案 1 :(得分:1)
如果您正在编写C ++代码。你应该使用new和delete。在C ++中编写C样式通常是不好的做法,因为C ++编译器不会产生最佳的二进制文件。如果你发现自己做了很多带有void *的类型转换,那么你可能做错了。
相反,使用C ++ 11智能指针!
答案 2 :(得分:0)
new
和delete
用于低级库开发。
有STL容器可用于缓冲区分配和解除分配。
在您的情况下,您可以尝试
std::vector<unsigned char> myBuffer(MAX_SIZE);