C++ 常见的C模式,但表示为C++;?
C编程中的一种常见模式涉及可变长度结构,例如:C++ 常见的C模式,但表示为C++;?,c++,c,design-patterns,protocol-buffers,C++,C,Design Patterns,Protocol Buffers,C编程中的一种常见模式涉及可变长度结构,例如: typedef struct { int length; char data[1]; } MyBuffer; 其中数据不是[1]的数组。相反,其可变长度由length定义 结构分配如下: MyBuffer* pBuff = malloc(sizeof(MyBuffer) + 100); 我想使用相同的模式,但是在C++代码中,所以使用新< /COD> >代码>删除,而不是 Malc >代码>免费< /代码> 这个模式可以在C
typedef struct {
int length;
char data[1];
} MyBuffer;
其中数据不是[1]的数组。相反,其可变长度由length
定义
结构分配如下:
MyBuffer* pBuff = malloc(sizeof(MyBuffer) + 100);
我想使用相同的模式,但是在C++代码中,所以使用<代码>新< /COD> >代码>删除<代码>,而不是<代码> Malc >代码>免费< /代码>
<>这个模式可以在C++代码中使用吗?怎么做 编辑因为一些答案和评论建议我切换到std::vector
:
我从第三方C库获得了结构定义MyBuffer
。在我的C++应用程序中,我需要分配缓冲区并调用C库中的函数。 在边界的“我的边”,我更喜欢保持C++,并将这个结构分配给C++。
但是我仍然需要把它传递给一个C库,它不能理解任何代码,比如“代码> STD::vector < /COD> .< /P> < P>如果你需要保持与你使用的C代码的兼容性,那么它就用C++工作,几乎没有变化(只是需要从<代码> MalCube()/代码>中返回)。
这是相当麻烦的,我承认……/P> < P>这不是C++中的惯用用法,也不需要。该语言提供了
std::vector
,它为您包装了大小和缓冲区,或者如果您在运行时不需要动态调整大小,C++11提供了std::array
编辑:这里要注意的关键是不要在堆上单独分配
向量
!如果将向量按值放在堆栈上或另一个对象中,并在构造时适当调整其大小,则使用的分配数量将与C版本(一个)完全相同。但是,你将使用习惯语言特性,防止自己产生各种各样的内存错误和/或泄漏。 C++中可以使用模板,而C元素缺少。模板参数确定数组的大小
template <unsigned N>
struct MyBufferTemplate {
int length;
char data[N];
};
我认为这会起作用,有几个语法错误
class MyBuffer {
// Important, this class must not have any virtual methods.
public:
void* operator new(size_t data_length) {
MyBuffer* buffer = static_cast<MyBuffer>(new char[sizeof(MyBuffer) + data_length]);
buffer->length = data_length;
return buffer;
}
private:
int length;
char data[1];
};
classmybuffer{
//重要信息,此类不能有任何虚拟方法。
公众:
void*运算符新(大小数据长度){
MyBuffer*buffer=static_cast(新字符[sizeof(MyBuffer)+数据长度];
缓冲区->长度=数据长度;
返回缓冲区;
}
私人:
整数长度;
字符数据[1];
};
编辑:
这种技术的一个主要缺点是调试构建很常见地覆盖全局运算符new,提供对缓冲区溢出和内存泄漏的运行时检查。我不确定这会与全球运营商new的非标准实现有多好的互动。就我个人而言,我会选择
malloc
和free
。但是,您可以全力以赴地使用new[]
、placementnew
和delete[]
:
#include <new>
struct MyBuffer {
int length;
char data[1];
};
MyBuffer* make_a_buffer(int size)
{
// allocate buffer large enough for what we want
char* raw_memory = new char[sizeof(MyBuffer) + size];
// call placement new to put a MyBuffer in the raw memory
MyBuffer* buffer = new (raw_memory) MyBuffer;
buffer->length = size;
return buffer;
}
void destroy_a_buffer(MyBuffer* buffer)
{
// in this case, MyBuffer has a trivial (default) destructor, so this isn't
// really needed, but in other cases you may need to call the
// destructor
//
// NOTE: there is placement new, but no placement delete
// this is the only way to correctly destroy the object
buffer->~MyBuffer();
// we've destroyed the object, and now we need to release the
// memory, luckily we know we got it from new[], so we can
// delete[] it
delete[] static_cast<char*>(static_cast<void*>(buffer));
}
#包括
结构MyBuffer{
整数长度;
字符数据[1];
};
MyBuffer*使_成为_缓冲区(整数大小)
{
//分配足够大的缓冲区以满足我们的需要
char*raw_memory=new char[sizeof(MyBuffer)+size];
//调用placement new将MyBuffer放入原始内存
MyBuffer*buffer=新的(原始内存)MyBuffer;
缓冲->长度=大小;
返回缓冲区;
}
无效销毁缓冲区(MyBuffer*buffer)
{
//在本例中,MyBuffer有一个普通的(默认)析构函数,所以它不是
//确实需要,但在其他情况下,您可能需要致电
//析构函数
//
//注意:有新放置,但没有删除放置
//这是正确销毁对象的唯一方法
buffer->~MyBuffer();
//我们已经摧毁了这个物体,现在我们需要释放
//内存,幸运的是我们知道我们从new[]获得了它,所以我们可以
//删除它
删除[]静态广播(静态广播(缓冲区));
}
如果您必须使用C结构,但是希望在C++中使用更好的方法,可以使用模板和继承的组合:
#include <iostream>
#include <memory>
#include <stdlib.h>
// Here's your C struct.
// Old C-style usage would be: MyBuffer* pBuff = malloc(sizeof(MyBuffer) + 100);
// Which effectively gives you a 101-byte array for 'data'.
// (1 for the original array, +100).
typedef struct {
int length;
char data[1];
} MyBuffer;
// This defines a generic template that inherits from whatever you want, and
// adds some padded space to the end of it. The 'extra_bytes' is equivalent
// to the '+100' you used to do in the c-style malloc trick (i.e. this still
// allocates a 101-byte array for 'data').
template<typename T, size_t extra_bytes>
struct ExtraBytes : public T {
char padding[extra_bytes];
};
// If you just want to wrap your one struct, you can use this. The constructor
// even sets the length for you.
template<size_t array_size>
struct MyBufferWrapper : public MyBuffer {
char padding[array_size - 1]; // 1 is already allocated to 'data'
MyBufferWrapper() {
length = array_size;
}
};
int main(int, char**) {
MyBuffer normal;
std::cout << "Sizeof normal MyBuffer = " << sizeof(normal) << "\tlength = "
<< normal.length << "\n"; // length is uninitialized
MyBuffer* pBuff = static_cast<MyBuffer*>(malloc(sizeof(MyBuffer) + 100));
std::cout << "Sizeof malloc'd MyBuffer = " << sizeof(*pBuff) << "\tlength = "
<< pBuff->length << "\n"; // length is uninitialized
ExtraBytes<MyBuffer, 100> extra_bytes;
std::cout << "Sizeof templated ExtraBytes = " << sizeof(extra_bytes)
<< "\tlength = " << extra_bytes.length << "\n"; // length is uninitialized
MyBufferWrapper<100> wrapper;
std::cout << "Sizeof Wrapped MyBuffer = " << sizeof(wrapper)
<< "\tlength = " << wrapper.length << "\n"; // length is set to 100
// If you reall auto heap = std::make_shared<MyBufferWrapper<100>>();
auto heap = std::make_shared<MyBufferWrapper<100>>();
std::cout << "Sizeof heap-allocated Wrapper = " << sizeof(*heap)
<< "\tlength = " << heap->length << "\n"; // length is 100
return 0;
}
#包括
#包括
#包括
//这是你的C结构。
//旧的C风格用法是:MyBuffer*pBuff=malloc(sizeof(MyBuffer)+100);
//这实际上为“数据”提供了一个101字节的数组。
//(原始阵列为1,+100)。
类型定义结构{
整数长度;
字符数据[1];
}我的缓冲区;
//这定义了一个通用模板,该模板继承您想要的任何内容,并且
//在其末尾添加一些填充空间。“额外字节”是等效的
//在c风格的malloc技巧中使用的“+100”(即,这仍然是
//为“数据”分配一个101字节的数组。
模板
结构外部字节:公共T{
字符填充[额外字节];
};
//如果你只想包装你的一个结构,你可以使用这个。构造器
//甚至为您设置长度。
模板
结构MyBufferWrapper:公共MyBuffer{
字符填充[array_size-1];//1已分配给“data”
MyBufferWrapper(){
长度=数组大小;
}
};
int main(int,char**){
MyBuffer正常;
STD::Cuth> P> C++ C++“ISH”的方法是将缓冲区描述为“简单的可复制”(C++ 11的LINGO,是C++ 98和2003中的“普通旧数据”的“POD”)。结构,但有一个微观的例外,即它有一个私有构造函数来阻止实例化。然后为该结构构造一个指针对象。下面是一个完整但简单的程序,其中包含该思想:
#include <cstdlib>
#include <cstring>
struct MyBuffer
{
int length;
char data[1];
private:
MyBuffer() {}
MyBuffer& operator =(MyBuffer& other) { return other; }
};
class MyBufferPointer
{
MyBuffer *bufptr_;
static std::size_t getsize(std::size_t array_size)
{
return sizeof (MyBuffer) + array_size * sizeof (char);
}
static MyBuffer *getbuf(std::size_t array_length)
{
std::size_t sz = getsize(array_length);
return static_cast<MyBuffer*>( malloc(sz) );
}
public:
MyBufferPointer() { bufptr_ = NULL; }
MyBufferPointer(std::size_t array_length)
{
bufptr_ = getbuf(array_length);
bufptr_->length = array_length;
}
MyBufferPointer(const MyBufferPointer &other)
{
const MyBuffer *op = other.bufptr_;
if (op == NULL)
{
bufptr_ = NULL;
}
else
{
bufptr_ = getbuf(op->length);
bufptr_->length = op->length;
std::size_t sz = op->length * sizeof op->data[0];
std::memmove( bufptr_->data, op->data, sz );
}
}
MyBufferPointer& operator =(const MyBufferPointer &other)
{
const MyBuffer *op = other.bufptr_;
if (op == NULL)
{
bufptr_ = NULL;
}
else
{
bufptr_ = getbuf(op->length);
bufptr_->length = op->length;
std::size_t sz = op->length * sizeof op->data[0];
std::memmove( bufptr_->data, op->data, sz );
}
return *this;
}
~MyBufferPointer() { if (bufptr_) free(bufptr_); }
std::size_t size() const
{
return bufptr_ ? bufptr_->length : 0;
}
// conventience operations for access to the data array:
char &operator [](std::size_t index) { return bufptr_->data[index]; }
char at(size_t index) const { return bufptr_->data[index]; }
MyBuffer* c_buffer() { return bufptr_; }
};
#include <iostream>
using namespace std;
int main()
{
MyBufferPointer bufp;
cout << "bufp().size() = " << bufp.size()
<< ", c_buffer=" << bufp.c_buffer() << endl;
bufp = MyBufferPointer(100);
cout << "bufp().size() = " << bufp.size()
<< ", c_buffer=" << bufp.c_buffer() << endl;
return 0;
}
#包括
#包括
结构MyBuffer
{
整数长度;
字符数据[1];
私人:
MyBuffer(){}
MyBuffer&operator=(MyBuffer&other){return other;}
};
类MyBufferPointer
{
我的缓冲区*bufptr_;
静态std::size\u t getsize(std::size\u t array\u size)
{
返回sizeof(MyBuffer)+数组_size*sizeof(char);
}
静态MyBuffer*getbuf(标准::大小数组长度)
{
std::size\u t sz=getsize(数组长度);
返回静态_cast(malloc(sz));
}
公众:
MyBufferPointer(){bufptr_U8;=NULL;}
MyBufferPointer(标准::大小数组长度)
{
bufptr_uu=getbuf(数组长度);
#include <new>
struct MyBuffer {
int length;
char data[1];
};
MyBuffer* make_a_buffer(int size)
{
// allocate buffer large enough for what we want
char* raw_memory = new char[sizeof(MyBuffer) + size];
// call placement new to put a MyBuffer in the raw memory
MyBuffer* buffer = new (raw_memory) MyBuffer;
buffer->length = size;
return buffer;
}
void destroy_a_buffer(MyBuffer* buffer)
{
// in this case, MyBuffer has a trivial (default) destructor, so this isn't
// really needed, but in other cases you may need to call the
// destructor
//
// NOTE: there is placement new, but no placement delete
// this is the only way to correctly destroy the object
buffer->~MyBuffer();
// we've destroyed the object, and now we need to release the
// memory, luckily we know we got it from new[], so we can
// delete[] it
delete[] static_cast<char*>(static_cast<void*>(buffer));
}
#include <iostream>
#include <memory>
#include <stdlib.h>
// Here's your C struct.
// Old C-style usage would be: MyBuffer* pBuff = malloc(sizeof(MyBuffer) + 100);
// Which effectively gives you a 101-byte array for 'data'.
// (1 for the original array, +100).
typedef struct {
int length;
char data[1];
} MyBuffer;
// This defines a generic template that inherits from whatever you want, and
// adds some padded space to the end of it. The 'extra_bytes' is equivalent
// to the '+100' you used to do in the c-style malloc trick (i.e. this still
// allocates a 101-byte array for 'data').
template<typename T, size_t extra_bytes>
struct ExtraBytes : public T {
char padding[extra_bytes];
};
// If you just want to wrap your one struct, you can use this. The constructor
// even sets the length for you.
template<size_t array_size>
struct MyBufferWrapper : public MyBuffer {
char padding[array_size - 1]; // 1 is already allocated to 'data'
MyBufferWrapper() {
length = array_size;
}
};
int main(int, char**) {
MyBuffer normal;
std::cout << "Sizeof normal MyBuffer = " << sizeof(normal) << "\tlength = "
<< normal.length << "\n"; // length is uninitialized
MyBuffer* pBuff = static_cast<MyBuffer*>(malloc(sizeof(MyBuffer) + 100));
std::cout << "Sizeof malloc'd MyBuffer = " << sizeof(*pBuff) << "\tlength = "
<< pBuff->length << "\n"; // length is uninitialized
ExtraBytes<MyBuffer, 100> extra_bytes;
std::cout << "Sizeof templated ExtraBytes = " << sizeof(extra_bytes)
<< "\tlength = " << extra_bytes.length << "\n"; // length is uninitialized
MyBufferWrapper<100> wrapper;
std::cout << "Sizeof Wrapped MyBuffer = " << sizeof(wrapper)
<< "\tlength = " << wrapper.length << "\n"; // length is set to 100
// If you reall auto heap = std::make_shared<MyBufferWrapper<100>>();
auto heap = std::make_shared<MyBufferWrapper<100>>();
std::cout << "Sizeof heap-allocated Wrapper = " << sizeof(*heap)
<< "\tlength = " << heap->length << "\n"; // length is 100
return 0;
}
#include <cstdlib>
#include <cstring>
struct MyBuffer
{
int length;
char data[1];
private:
MyBuffer() {}
MyBuffer& operator =(MyBuffer& other) { return other; }
};
class MyBufferPointer
{
MyBuffer *bufptr_;
static std::size_t getsize(std::size_t array_size)
{
return sizeof (MyBuffer) + array_size * sizeof (char);
}
static MyBuffer *getbuf(std::size_t array_length)
{
std::size_t sz = getsize(array_length);
return static_cast<MyBuffer*>( malloc(sz) );
}
public:
MyBufferPointer() { bufptr_ = NULL; }
MyBufferPointer(std::size_t array_length)
{
bufptr_ = getbuf(array_length);
bufptr_->length = array_length;
}
MyBufferPointer(const MyBufferPointer &other)
{
const MyBuffer *op = other.bufptr_;
if (op == NULL)
{
bufptr_ = NULL;
}
else
{
bufptr_ = getbuf(op->length);
bufptr_->length = op->length;
std::size_t sz = op->length * sizeof op->data[0];
std::memmove( bufptr_->data, op->data, sz );
}
}
MyBufferPointer& operator =(const MyBufferPointer &other)
{
const MyBuffer *op = other.bufptr_;
if (op == NULL)
{
bufptr_ = NULL;
}
else
{
bufptr_ = getbuf(op->length);
bufptr_->length = op->length;
std::size_t sz = op->length * sizeof op->data[0];
std::memmove( bufptr_->data, op->data, sz );
}
return *this;
}
~MyBufferPointer() { if (bufptr_) free(bufptr_); }
std::size_t size() const
{
return bufptr_ ? bufptr_->length : 0;
}
// conventience operations for access to the data array:
char &operator [](std::size_t index) { return bufptr_->data[index]; }
char at(size_t index) const { return bufptr_->data[index]; }
MyBuffer* c_buffer() { return bufptr_; }
};
#include <iostream>
using namespace std;
int main()
{
MyBufferPointer bufp;
cout << "bufp().size() = " << bufp.size()
<< ", c_buffer=" << bufp.c_buffer() << endl;
bufp = MyBufferPointer(100);
cout << "bufp().size() = " << bufp.size()
<< ", c_buffer=" << bufp.c_buffer() << endl;
return 0;
}