当它们在内存中表示时,C++对象是否与C结构相同?
例如,使用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("String: %s", (char *) &testObj->myVarChar); }
我认为C++不允许+
为内置char *
类型重载运算符.
所以我想创建自己的轻量级字符串类,它没有额外的开销std::string
.我认为std::string
是连续的代表:
(int)length, (char[])data
我想要完全相同的功能,但没有前缀长度(节省8字节开销).
这是我用来测试的代码,但它导致了段错误
#includeusing 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 << "'"; }
编辑:没有人真正明白我想做什么.是的我知道我可以有一个指向类中字符串的指针,但比普通的cstring贵8个字节,我想要完全相同的内部表示.谢谢你的尝试
编辑:我想要实现的最终结果是能够使用+运算符,与使用strcat等相比没有额外的内存使用量
const char * operator+(const char * first, const char * second);
RnR.. 16
你不应该浪费你的时间来编写字符串类 - 这是人们花时间编写它们的原因,并且认为他们编写它们是天真的,因为他们想要创建大的混淆和过度的代码,你可以在几个小时内轻松改进.
例如,你的代码在赋值运算符中的内存重新分配具有二次复杂度 - 每次分配大于1个字符的sting将使用大于1个字节的新内存块,导致在这样的"少量"赋值后出现大内存碎片 - 你节省了几个字节,但可能会丢失兆字节来解决空间和内存页面碎片问题.
同样以这种方式设计你无法有效地实现+ =运算符,而不是仅仅复制附加的字符串,在大多数情况下你总是需要复制整个字符串 - 因此如果你将一个小字符串附加到一个更大的字符串,那么再次达到二次复杂度一次几次.
抱歉,你的想法看起来有很大的机会变得难以维持,并且比std :: string这样的典型字符串实现的效率低.
别担心 - 这对于"编写自己更好的标准容器版本"的所有好主意来说都是如此":)
你不应该浪费你的时间来编写字符串类 - 这是人们花时间编写它们的原因,并且认为他们编写它们是天真的,因为他们想要创建大的混淆和过度的代码,你可以在几个小时内轻松改进.
例如,你的代码在赋值运算符中的内存重新分配具有二次复杂度 - 每次分配大于1个字符的sting将使用大于1个字节的新内存块,导致在这样的"少量"赋值后出现大内存碎片 - 你节省了几个字节,但可能会丢失兆字节来解决空间和内存页面碎片问题.
同样以这种方式设计你无法有效地实现+ =运算符,而不是仅仅复制附加的字符串,在大多数情况下你总是需要复制整个字符串 - 因此如果你将一个小字符串附加到一个更大的字符串,那么再次达到二次复杂度一次几次.
抱歉,你的想法看起来有很大的机会变得难以维持,并且比std :: string这样的典型字符串实现的效率低.
别担心 - 这对于"编写自己更好的标准容器版本"的所有好主意来说都是如此":)
struct myObj { //... char myVarChar; };
这不行.您需要一个固定大小的数组,一个指向char的指针或使用struct hack.您将无法为此指定指针myVarChar
.
所以我想创建自己的轻量级字符串类,它没有额外的开销std :: string has.
您指的是多少额外开销?您是否经过测试和测量,看看它std::string
是否真的成为瓶颈?
我认为std :: string是连续表示的
是的,主要是字符缓冲部分.但是,以下内容:
(INT)的长度(字符[])的数据
标准不要求.翻译:字符串实现不需要使用其数据的这种特定布局.它可能有额外的数据.
现在,您的轻量级字符串类出现了错误:
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; };
哇.你要做的是彻底滥用C++,如果它有效的话,完全依赖于编译器,并且肯定会让你有一天在TheDailyWTF中登陆.
你得到段错误的原因可能是因为你的operator =将对象重新分配到不同的地址,但是你没有更新main中的myString指针.我甚至在这一点上甚至称它为一个对象,因为从未调用任何构造函数.
我认为你要做的是让pString成为一个更聪明的指向字符串的指针,但是你会发现它错了.让我来解决一下.
#includeusing 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() << "'";
}
现在我不会使用malloc而是使用new/delete,但我保留了尽可能接近原始的内容.
你可能会认为你在你的课堂上浪费了一个指针的空间,但你不是 - 你正在为你以前保留在主要指针中的指针进行交易.我希望这个例子说清楚 - 变量大小相同,malloc/realloc分配的额外内存量也是一样的.
pString myString; char * charString; assert(sizeof(myString) == sizeof(charString));
PS我应该指出,这段代码仍然需要很多工作,它充满了漏洞.你需要一个构造函数来初始化指针,一个析构函数可以在它完成时释放它,只是为了初学者.你也可以自己实现operator +.