Realloc()/在C++;对于字符串实现 当它们在内存中表示时,C++对象与C结构相同吗?< /强>
例如,使用C,我可以做如下操作:Realloc()/在C++;对于字符串实现 当它们在内存中表示时,C++对象与C结构相同吗?< /强> ,c++,realloc,C++,Realloc,例如,使用C,我可以做如下操作: struct myObj { int myInt; char myVarChar; }; int main() { myObj * testObj = (myObj *) malloc(sizeof(int)+5); testObj->myInt = 3; strcpy((char*)&testObj->myVarChar, "test"); printf(
struct myObj {
int myInt;
char myVarChar;
};
int main() {
myObj * testObj = (myObj *) malloc(sizeof(int)+5);
testObj->myInt = 3;
strcpy((char*)&testObj->myVarChar, "test");
printf("String: %s", (char *) &testObj->myVarChar);
}
template<int max_size> class MyString
{
public:
size_t size;
char contents[max_size];
public:
MyString(const char* data);
};
<>我不认为C++允许重载<代码> +/Cux>运算符,用于内置的<代码> char */COD>类型。< /P>
因此,我想创建自己的轻量级字符串类,它没有std::string
所具有的额外开销。我认为std::string
是连续表示的:
(int)length, (char[])data
我想要完全相同的功能,但不加前缀的长度(节省8字节的开销)
这是我用来测试的代码,但它会导致一个segfault
#include <iostream>
using namespace std;
class pString {
public:
char c;
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
realloc(this, strlen(buff)+1);
memcpy(this, buff, strlen(buff));
*(this+strlen(buff)) = '\0';
return this;
};
struct myObj {
int myInt;
char myVarChar;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing";
cout << "'" << (char *) myString << "'";
}
不能更改C/C++中的对象/结构的大小。它们的大小在编译时是固定的
内存中表示的对象是C++对象,与C结构相同。
严格地说,不是。一般来说,是的。C++类和结构在内存布局与C结构上是相同的,除了:- 位字段具有不同的打包规则
- 大小在编译时是固定的
- 如果存在任何虚拟函数,编译器将向内存布局添加vtable条目
- 如果对象继承基类,则新类的布局将附加到基类布局,包括vtable(如果有)
char*
类型创建运算符+
重载。正常行为是指针运算std::string
重载operator+
以将char*
数据附加到字符串中。该字符串作为C字符串以及其他信息存储在内存中。c_str()
成员函数返回指向内部char
数组的指针
在C示例中,您依赖于未定义的行为。不要像那样realloc
。它可能会导致不好的事情,即奇怪的错误
你的C++示例也在做<代码> ReLoLc(这个)中做了坏事。相反,您应该携带一个
char*
并获得一个new char[]
缓冲区来存储字符,而不是realloc()
。此类realloc
的行为未定义
struct myObj {
//...
char myVarChar;
};
这行不通。您要么需要一个固定大小的数组,一个指向char的指针,要么使用struct hack。您将无法分配指向此myVarChar
的指针
所以我想创建我自己的轻量级string类,它没有额外的开销std::string
你指的是什么额外的开销?您是否测试和测量了std::string
是否真的是一个瓶颈
我认为std::string是连续表示的
是的,主要是字符缓冲区部分。但是,以下方面:
/* a light-weight string class */
class lwstring {
public:
lwstring(); // default ctor
lwstring(lwstring const&); // copy ctor
lwstring(char const*); // consume C strings as well
lwstring& operator=(lwstring const&); // assignment
~lwstring(); // dtor
size_t length() const; // string length
bool empty() const; // empty string?
private:
char *_myBuf;
size_t _mySize;
};
(int)长度(char[])数据
本标准不要求。翻译:字符串实现不需要使用其数据的这种特定布局。它可能有额外的数据
现在,您的轻量级字符串类出现错误:
class pString {
public:
char c; // typically this is implementation detail, should be private
pString * pString::operator=(const char *);
// need ctors, dtors at least as well
// won't you need any functions on strings?
};
尝试以下方法:
/* a light-weight string class */
class lwstring {
public:
lwstring(); // default ctor
lwstring(lwstring const&); // copy ctor
lwstring(char const*); // consume C strings as well
lwstring& operator=(lwstring const&); // assignment
~lwstring(); // dtor
size_t length() const; // string length
bool empty() const; // empty string?
private:
char *_myBuf;
size_t _mySize;
};
您的类定义/用法有很多错误。如果要存储字符串,应该使用指针类型,比如char*a成员,而不是单个char。使用单个字符意味着只分配一个字符的内存 另一个错误是分配代码,您可以在此代码上执行realloc-您可以潜在地更改分配的内存,但不能更改其值。您必须将结果分配给此以实现此目标(
this=(*pString)realloc(this,strlen(buff+1));
),无论如何,这是一种非常糟糕的做法。在char*成员上使用realloc要好得多
<> P>不幸的是C++ C++有,你必须使用新的和删除,自己做任何拷贝。 为什么你用C类写C,为什么不使用C++? < p>如果你想要的东西基本上与<代码> STD::String 完全相同,除了它不知道字符串有多长,你应该学习<代码> STD::String 什么操作符重载了它,等等,然后模仿它,只是你想要的差异 然而,这不太可能有任何实际意义 关于您的最新更新,您说您想要一种设计,在这种设计中,通用应用程序代码将传递裸指针到堆对象。没有自动清理
很简单,这是一个非常糟糕的主意。您不应该浪费时间编写字符串类-人们首先花时间编写字符串类是有原因的,认为他们编写它们是因为他们想创建大的混乱和繁杂的代码,您可以在数小时内轻松改进 例如,对于赋值运算符中的内存重新分配,您的代码具有二次复杂性-每分配一个大于1个字符的sting将使用一个大于1字节的新内存块,从而在“几个”之后产生大内存碎片像这样的分配-您可以节省一些字节,但可能会丢失兆字节来处理空间和内存页碎片 同样以这种方式设计,您也无法有效地实现+=运算符,因为在大多数情况下,您总是需要复制整个字符串,从而在将小字符串多次附加到较大字符串的情况下,再次达到二次复杂度 很抱歉,您的想法很有可能会变得很难维护,并且效率比典型的字符串实现(如std::string)低几个数量级
别担心——这在实践中是正确的“编写您自己的标准容器的更好版本”的所有伟大想法:)如果您想要性能,您可以编写
class pstring
{
public:
int myInt;
char myVarchar;
void* operator new(size_t size, const char* p);
void operator delete(void* p);
};
void* pstring::operator new(size_t size, const char* p)
{
assert(sizeof(pstring)==size);
char* pm = (char*)malloc(sizeof(int) + strlen(p) +1 );
strcpy(sizeof(int)+pm, p);
*(int*)(pm) = strlen(p); /* assign myInt */
return pm;
}
void pstring::operator delete(void* p)
{
::free(p);
}
pstring* ps = new("test")pstring;
delete ps;
#include <iostream>
using namespace std;
class pString {
public:
char c[1];
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
realloc(this->c, strlen(buff)+1);
memcpy(this->c, buff, strlen(buff));
*(this->c+strlen(buff)) = '\0';
return this;
};
struct myObj {
int myInt;
char myVarChar;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing vijay";
cout << "'" << ((char*)myString << "'";
}
This should work. But its not advisable.
#include <iostream>
using namespace std;
class pString {
public:
char * c;
pString & operator=(const char *);
const char * c_str();
};
pString & pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) this->c << endl;
c = (char *) malloc(strlen(buff)+1);
memcpy(c, buff, strlen(buff));
*(c+strlen(buff)) = '\0';
return *this;
};
const char * pString::c_str() {
return c;
}
int main() {
pString myString;
myString = "testing";
cout << "'" << myString.c_str() << "'";
pString myString;
char * charString;
assert(sizeof(myString) == sizeof(charString));
class light_string {
public:
light_string(const char* str) {
size_t length = strlen(str);
char* buffer = new char[sizeof(size_t) + length + 1];
memcpy(buffer, &length, sizeof(size_t));
memcpy(buffer + sizeof(size_t), str, length);
memset(buffer + sizeof(size_t) + length, 0, 1);
m_str = buffer + sizeof(size_t);
}
~light_string() {
char* addr = m_str - sizeof(size_t);
delete [] addr;
}
light_string& operator =(const char* str) {
light_string s = str;
std::swap(*this, s);
return *this;
}
operator const char*() {
return m_str;
}
size_t length() {
return
*reinterpret_cast<size_t *>(m_str - sizeof(size_t));
}
private:
char* m_str;
};
int main(int argc, char* argv[])
{
cout<<sizeof(light_string)<<endl;
return 0;
}
#include <iostream>
using namespace std;
class pString {
public:
char c;
pString * pString::operator=(const char *);
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
cout << "Address of this->c: " << (uint32_t) &this->c << endl;
char *newPoint = (char *)realloc(this, strlen(buff)+1);
memcpy(newPoint, buff, strlen(buff));
*((char*)newPoint+strlen(buff)) = '\0';
cout << "Address of this After: " << (uint32_t) newPoint << endl;
return (pString*)newPoint;
};
int main() {
pString * myString = (pString *) malloc(sizeof(pString));
*myString = "testing";
cout << "Address of myString: " << (uint32_t) myString << endl;
cout << "'" << (char *) myString << "'";
}
this = (pString*) newPoint;
void concatenate(std::string& s, const char* c) {
s.reserve(s.size() + strlen(c));
s.append(c);
}
#include <iostream>
using namespace std;
struct pString {
/* No Member Variables, the data is the object */
/* This class cannot be extended & will destroy a vtable */
public:
pString * pString::operator=(const char *);
};
pString& operator+(pString& first, const char *sec) {
int lenFirst;
int lenSec = strlen(sec);
void * newBuff = NULL;
if (&first == NULL)
{
cout << "NULL" << endl;
lenFirst = 0;
newBuff = malloc(sizeof(pString)+lenFirst+lenSec+1);
} else {
lenFirst = strlen((char*)&first);
newBuff= (pString*)realloc(&first, lenFirst+lenSec+1);
}
if (newBuff == NULL)
{
cout << "Realloc Failed"<< endl;
free(&first);
exit(0);
}
memcpy((char*)newBuff+lenFirst, sec, lenSec);
*((char*)newBuff+lenFirst+lenSec) = '\0';
cout << "newBuff: " << (char*)newBuff << endl;
return *(pString*)newBuff;
};
pString * pString::operator=(const char * buff) {
cout << "Address of this: " << (uint32_t) this << endl;
char *newPoint = (char *)realloc(this, strlen(buff)+200);
memcpy(newPoint, buff, strlen(buff));
*((char*)newPoint+strlen(buff)) = '\0';
cout << "Address of this After: " << (uint32_t) newPoint << endl;
return (pString*)newPoint;
};
int main() {
/* This doesn't work that well, there is something going wrong here, but it's just a proof of concept */
cout << "Sizeof: " << sizeof(pString) << endl;
pString * myString = NULL;
//myString = (pString*)malloc(1);
myString = *myString = "testing";
pString& ref = *myString;
//cout << "Address of myString: " << myString << endl;
ref = ref + "test";
ref = ref + "sortofworks" + "another" + "anothers";
printf("FinalString:'%s'", myString);
}
class pString {
char txt[];
}
class otherString : pString { // This cannot work because now the
size_t len; // the flexible array is not at the
} // end
class MyConcatString;
class MyString {
public:
MyString(const MyConcatString& c) {
reserve(c.l.length()+c.r.lenght());
operator = (l);
operator += (r);
}
MyConcatString operator + (const MyString& r) const {
return MyConcatString(*this, r);
}
};
class MyConcatString {
public:
friend class MyString;
MyConcatString(const MyString& l, const MyString& r):l(l), r(r) {};
...
operator MyString () {
MyString tmp;
tmp.reserve(l.length()+r.length());
tmp = l;
tmp += r;
return tmp;
}
private:
MyString& l;
MyString& r;
}
MyString a = "hello";
MyString b = " world";
MyString c = a + b;