Overallocating with new/delete - c++

Using malloc and free, it is easy to allocate structures with extra data beyond the end. But how do I accomplish the same with new/ delete?
I know I could use placement new syntax along with malloc for the allocation part, but will delete work properly and portably if I place an object in memory allocated by malloc?
What I want to accomplish is the same as the following example, but using new/ delete instead of malloc/ free, so that constructors/destructors will be called properly:
#include <cstdlib>
#include <cstring>
#include <iostream>
class Hamburger {
int tastyness;
public:
char *GetMeat();
};
char *Hamburger::GetMeat() {
return reinterpret_cast<char *>(this) + sizeof(Hamburger);
}
int main(int argc, char* argv[])
{
Hamburger* hb;
// Allocate a Hamburger with 4 extra bytes to store a string.
hb = reinterpret_cast<Hamburger*>(malloc(sizeof(Hamburger) + 4));
strcpy(hb->GetMeat(), "yum");
std::cout << "hamburger is " << hb->GetMeat() << std::endl;
free(hb);
}
Output: hamburger is yum

You can do this without resorting to malloc/free or undefined behavior (I'm not sure about the reinterpret_cast, but at least construction/destruction can be done just fine).
To allocate the memory you can just call the global operator new directly. After that you use good old placement new to construct the object there. You have to guard the ctor-call though, since the "placement delete" function that's called if the ctor fails will not release any memory but just do nothing (just as placement new does nothing).
To destroy the object afterwards you can (and may) call the destructor directly, and to release the memory you can call the global operator delete.
I think it should also be OK to just delete it as you would any normal object, since calling the destructor and global operator delete afterwards is just what the normal delete will do, but I'm not 100% sure.
Your example modified like that:
#include <cstdlib>
#include <cstring>
#include <iostream>
class Hamburger {
int tastyness;
public:
char *GetMeat();
};
char *Hamburger::GetMeat() {
return reinterpret_cast<char *>(this) + sizeof(Hamburger);
}
int main(int argc, char* argv[])
{
Hamburger* hb;
// Allocate space for a Hamburger with 4 extra bytes to store a string.
void* space = operator new(sizeof(Hamburger) + 4);
// Construct the burger in that space
hb = new (space) Hamburger; // TODO: guard ctor call (release memory if ctor fails)
strcpy(hb->GetMeat(), "yum"); // OK to call member function on burger now
std::cout << "hamburger is " << hb->GetMeat() << std::endl;
// To delete we have to do 2 things
// 1) call the destructor
hb->~Hamburger();
// 2) deallocate the space
operator delete(hb);
}

If I were you, I'd use placement new and an explicit destructor call instead of delete.
template< typename D, typename T >
D *get_aux_storage( T *x ) {
return reinterpret_cast< D * >( x + 1 );
}
int main() {
char const *hamburger_identity = "yum";
void *hamburger_room = malloc( sizeof( Hamburger )
+ strlen( hamburger_identity ) + 1 );
Hamburger *hamburger = new( hamburger_room ) Hamburger;
strcpy( get_aux_storage< char >( hamburger ), hamburger_identity );
cout << get_aux_storage< char const >( hamburger ) << '\n';
hamburger->~Hamburger(); // explicit destructor call
free( hamburger_room );
}
Of course, this kind of optimization should only be done after profiling has proven the need. (Will you really save memory this way? Will this make debugging harder?)
There might not be a significant technical difference, but to me new and delete signal that an object is being created and destroyed, even if the object is just a character. When you allocate an array of characters as a generic "block," it uses the array allocator (specially suited to arrays) and notionally constructs characters in it. Then you must use placement new to construct a new object on top of those characters, which is essentially object aliasing or double construction, followed by double destruction when you want to delete everything.
It's better to sidestep the C++ object model with malloc/free than to twist it to avoid dealing with data as objects.
Oh, an alternative is to use a custom operator new, but it can be a can of worms so I do not recommend it.
struct Hamburger {
int tastyness;
public:
char *GetMeat();
static void *operator new( size_t size_of_bread, size_t size_of_meat )
{ return malloc( size_of_bread + size_of_meat ); }
static void operator delete( void *ptr )
{ free( ptr ); }
};
int main() {
char const *hamburger_identity = "yum";
size_t meat_size = strlen( hamburger_identity ) + 1;
Hamburger *hamburger = new( meat_size ) Hamburger;
strcpy( hamburger->GetMeat(), hamburger_identity );
cout << hamburger->GetMeat() << '\n';
}

Urgh. Well, let's see. You definitely can't allocate with new/malloc and dispose with free/delete. You have to use matching pairs.
I suppose you could use "hp = new char[sizeof(Hamburger) + 4]" and "delete[]((char *) hp)", along with explicit constructor/destructor calls, if you really wanted to do this.
The only reason I can think why you'd want to do this would be you didn't have the Hamburger source -- i.e., it was a library class. Otherwise you'd just add a member to it! Can you explain why you'd want to use this idea?

There is another way that you could approach this if you have a reasonably constrained set of padding amounts. You could make a template class with the padding amount as the template parameter and then instantiate it with the set of possible padding amounts. So if, for example, you knew that you were only going to need padding of 16, 32, or 64 bytes, you could do it like this:
template <int Pad>
class Hamburger {
int tastiness;
char padding[Pad];
};
template class Hamburger<16>;
template class Hamburger<32>;
template class Hamburger<64>;

Is there any reason why the straightforward, easy and safe way is not applicable?
class Hamburger {
public:
void Extend( const std::string& pExtension) {
mContent += pExtension;
}
const std::string& GetMeat() ...
private:
std::string mContent;
};
int main() {
Hamburger hb;
hb.Extend("yum");
std::cout << "hamburger is " << hb.GetMeat() << std::endl;
}

Related

Initialize a string with a char pointer with zero-copy

Say I am given a long and null-terminated cstring as char* text_ptr. I own text_ptr and I am responsible of free()ing it. Currently, I use text_ptr and free() it each time after use.
I try to improve memory safety a bit by wrapping it in a C++ class so that I can enjoy the benefit of RAII. There could be many ways to achieve it. A naive way is: string text_ptr(text_ptr);. However, by doing so, memory is copied once and I still need to manually free() my text_ptr. It would be better if I can avoid memory copy and free() (as this text_ptr is created frequently, performance could take a big hit if I copy it each time). My current thought:
Is it possible to transfer the ownership of text_ptr to a string text_str? Hypothetically, I do text_str.data() = text_ptr;.
Thanks
std::string can't receive ownership of an external buffer. The best you can do is std::unique_ptr.
By default std::unique_ptr will use delete (or delete[]), but you need std::free(), so a custom deleter is required:
#include <cstdlib>
#include <memory>
struct FreeDeleter
{
void operator()(void *p) const
{
std::free(p);
}
};
int main()
{
std::unique_ptr<char[], FreeDeleter> ptr((char *)malloc(42));
}
If you also store the length, you can construct a temporary std::string_view from pointer+length when needed, to conveniently read the string.
Or, a oneliner: std::unique_ptr<char[], std::integral_constant<void(*)(void *), std::free>>.
Another one for C++20: std::unique_ptr<char[], decltype([](void *p){std::free(p);})>.
An idea (not sure it’s a good one, tho)
#include <iostream>
#include <string_view>
#include <cstring>
#include <memory>
struct my_string_view : public std::string_view
{
using std::string_view::string_view;
std::shared_ptr<char[]> _data;
explicit my_string_view( char * data )
: std::string_view(data)
, _data{data, free}
{ }
};
void f( const my_string_view & s )
{
std::cout << "f: \"" << s << "\"\n";
}
int main()
{
my_string_view s( strdup( "Hello world!" ) );
f( s );
std::cout << "main: \"" << s << "\"\n";
}
(This version requires C++17. For older versions of the standard you’ll have to specify the default_deleter<char[]>() explicitly.)

Passing a string as a const char*

I have access to a class (not written by me) that takes a const char* as a parameter in the constructor. If I have a string that I want to pass the value of as a parameter, what is the safe way to pass it, keeping in mind that the string and the class object may have different scopes?
I don't have access to the source code for the class, so don't assume it's doing something sane like copying the string into a class member.
As a concrete example, this doesn't work:
#include <iostream>
#include <string>
class example {
public:
example(const char*);
const char* str;
};
example::example(const char* a) : str(a) {}
int main() {
std::string* a=new std::string("a");
example thisDoesntWork(a->c_str());
std::cout << thisDoesntWork.str << std::endl;
delete a;
std::cout << thisDoesntWork.str << std::endl; //The pointer is now invalid
a=new std::string("b");
std::cout << thisDoesntWork.str << std::endl;
}
Replacing the constructor with this works (so far as I can tell) but is clearly pretty awful:
example thisDoesWorkButIsAwful((new const std::string(*a))->c_str()); //Memory leak!
Similarly:
char* buffer=new char[a->size()+1];
strcpy(buffer,a->c_str()); //with #include <string.h> added up top
example(buffer);
But again, this is prone to memory leaks.
My main idea at the moment is to make a wrapper class around example that copies the string into a char * buffer and deletes the buffer when it goes out of scope, but that seems a little heavy-handed. Is there an easier/better way?
Fundamentally, something needs to hold on to the memory - either you do it yourself or have it done automatically.
One way to do it automatically:
class SuperThatHoldsIt
{
std::string mString ;
SuperThatHoldsIt ( std::string const& str )
: mString ( str ) { }
} ;
class HoldingExample
: private SuperThatHoldsIt
, public example
{
holdingExample ( std::string const& string )
: SuperThatHoldsIt ( string )
, example ( mString.c_str() )
{ }
} ;
Then create it in a std::shared_ptr (or boost::shared_ptr) which will hold on to it.
std::string myString ( "Hello, world!" ) ;
std::shared_ptr<HoldingExample> value = std::make_shared<HoldingExample> ( myString ) ;
Now this holds onto the memory AND the structure.
Notes:
The reason HoldingExample derives from two supers is to that the order of constructors will work out because superclasses are always initialized before local variables. This means we have to construct example before our own member variables, but we can always initialize a superclass's and use its member variables.
If you pass this into a function, like
callFunction ( *value ) ;
If they hold on to that const char* after you've let go of your value, then you'll still have a leak and you really can't get around that.

Detecting stack or heap allocation

I have a class I’d like to be able to set a flag in that says if it is heap allocated so it can properly clean up after itself and not try to delete itself if it’s on the stack. The problem is...I can’t seem to override both new and the constructors at the same time. So it goes from my new overload that sets the isHeapAllocated flag and then into my constructor which resets the flag.
void* String8::operator new(size_t size)
{
String8* string = (String8*)malloc(size);
if(string == null)
Exception("allocation fail : no free memory");
string->isHeapAllocated = true;
return string;
}
String8::String8()
{
isHeapAllocated = false;
}
So new String8() sets the isHeapAllocated flag and then resets it to false. Is there any way to do this?
It will not work as intended:
The new operator return unitialized memory to be given to the constructor.
You -correctly- do String8* string = (String8*)malloc(size);, but *string, at this stage is not yet a String8 object: it is just the memory bulk that will contain it.
So string->isHeapAllocated = true; in fact sets a flag inside a not yet constructed object (that's UB).
Admitting this will not compromise the OS process, so that the program will not crash (you write memory that belongs already to you, after all ...), when you will later do something like String8* ptr = new String8;, after new returns, the String8::String8 constructor is called, and the member will be set back to "false" independently on what you did in the new operator overload.
The idiomatic way to manage C++ objects is let who allocate to be responsible to deallocate.
(and if "who" it is the stack, it just do that by definition).
This is a bad idea, but here’s a way to do it that doesn’t invoke undefined behaviour.
#include <iostream>
#include <memory>
#include <set>
using namespace std;
class C {
public:
void* operator new(size_t size) {
C* c = static_cast<C*>(::operator new(size));
heap_instances.insert(c);
return c;
}
C() : heap_allocated(heap_instances.find(this) != heap_instances.end()) {}
const bool heap_allocated;
private:
static set<const C*> heap_instances;
};
set<const C*> C::heap_instances;
int main(int argc, char** argv) {
cout << boolalpha;
C stack;
cout << stack.heap_allocated << '\n'; // false
C* heap_nozero = new C;
cout << heap_nozero->heap_allocated << '\n'; // true
delete heap_nozero;
C* heap_zero = new C();
cout << heap_zero->heap_allocated << '\n'; // true
delete heap_zero;
}
You can remove pointers from heap_instances when you’re done with them, of course, and use a more suitable container if you’re running in a multithreaded environment. But again, I wouldn’t recommend that you actually do this—deciding behaviour based on allocation is not something an object ought to do.
The only legitimate reason I can think of for this is to enable delete this. While that’s safe if you’re careful not to access members after the object’s suicide, it’s usually saner to let objects manage the lifetimes of other objects.
Note that the construtor gets called if it is allocated on the stack or the heap and there is no way for the object to detect if it was allocated on the stack or in the heap.
To create an object at the stack you don't use any memory allocation functions like this
String8 myString;
To create it on the heap you do
String8 *myString = new String8();
note that you do have to do the cleanup manually after not using the object anymore.
For the use of Heap objects bound to stack scope you can check out the RAII principle which is used intensly by c++ programs (see here for a better explaination of the difference of heap allocation and stack allocation).
Not sure why you need this, really. It's caller's responsibility to call delete if needed and your class's destructor should not be different whether it's called on the object on stack or on the heap... But, maybe, you are doing some special purpose class... Here is my quick take on it.
EDIT: You should also, probably, add custom delete operator to your class, unless you know that global delete calls a deallocation function that matches the allocation function you use in your custom new operator.
#include <cstdlib>
#include <iostream>
namespace so
{
class _test_
{
private:
static bool flag_allocation_heap;
bool flag_heap;
public:
_test_()
: flag_heap( flag_allocation_heap )
{
flag_allocation_heap = 0;
std::cout << flag_heap << std::endl;
}
void * operator new( std::size_t _size )
{
_test_ * test_ = static_cast< _test_ * >( std::malloc( _size ) );
flag_allocation_heap = 1;
return ( test_ );
}
};
bool _test_::flag_allocation_heap = 0;
} // namespace so
int main()
{
so::_test_ test_stack_;
so::_test_ * test_memory_ = new so::_test_;
delete test_memory_;
return( 0 );
}
Output:
0
1

Where do I have to free the memory after allocating?

I am trying to do some practice for memory allocation.
I have the below code which is working but have two questions.
Where do I have to use delete [ ] to free the memory after allocating?
Why is the output for this code at function when using show() function is CDcar?.
#include <cstdlib>
#include <new>
#include <iostream>
#include <cstring>
using namespace std;
class automobile {
private:
char (*function)[30];
char *type;
double speed;
public:
automobile ( );
automobile (double , char *);
void speed_up (double);
void speed_down(double);
const char * get_function ( ) const;
void show ( );
};
automobile::automobile ( ) {
speed = 0;
function = new char [1][30];
strcpy(function[1], "CD player with MP3");
type = new char [4];
strcpy(type, "car");
}
automobile::automobile(double spd, char * fn ) {
int sz;
}
void automobile::show ( ) {
cout << "This is a " << type << " and it has the following functions: " << function[1] << ", and its speed is " << speed << " km/h\n";
}
int main ( ) {
automobile car;
car.show ( );
return 0;
}
this is the output:
This is a car and it has the following functions: CDcar, and its speed is 0 km/h
I thought the output shoud be this:
This is a car and it has the following functions: CD player with MP3, and its speed is 0 km/h
Please advise
Where do I have to use delete [ ] to free the memory after allocating?
Ideally nowhere. new and delete are features of C++ that are not suitable for most code. They are error-prone and too low-level. They're only useful for basic building blocks.
The code shown could benefit from basic building blocks like std::string, std::vector.
The code shown also invokes undefined behaviour at least in one place:
function = new char [1][30];
strcpy(function[1], "CD player with MP3");
Arrays are 0-based, so function[1] is an out-of-bounds access.
You should call delete[] in the destructor of your class.
//Called when your class is destroyed.
automobile::~automobile()
{
delete[] function;
}
You should place the delete[] for function and type within the destructor ~automobile (you don't have one currently, so you'll have to create it).
Regarding the output: Your character is array is not well defined. Consider using std::vector<string> for such things (much easier).
Your output is incorrect b/c of the following:
speed = 0;
function = new char [1][30];
strcpy(function[1], "CD player with MP3");
This should be
speed = 0;
function = new char [1][30];
strcpy(function[0], "CD player with MP3");
and when you output you should be cout'ing function[0] instead of function[1].
Having said this, you should almost always try to eliminate manual calls to new and delete. It helps with maintainability and it helps keep code exception safe. In this case you can get this for free by using vectors and strings provided by the standard C++ library. In a more general sense, you want to follow the RAII Idiom. This will help C++ and memory management from shaving a couple of years off your life during your studies/career.
Inside ~automobile destructor.

Realloc()/Resize an object in C++ for a string implementation

When they are represented in memory, are C++ objects the same as C structs?
For example, with C, I could do something like this:
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);
}
I don't think C++ allows overloading the + operator for the built-in char * type.
So i'd like to create my own lightweight string class which has no extra overhead that std::string has. I think std::string is represented contiguously:
(int)length, (char[])data
I want exactly the same functionality but without prefixing the length (saving 8 bytes overhead).
Here is the code i'm using to test, but it results in a 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 << "'";
}
Edit: nobody really understands what i want to do. Yes i know i can have a pointer to the string in the class but thats 8 bytes more expensive than a plain cstring, i wanted exactly the same internal representation. Thanks for trying though
Edit: The end result of what i wanted to achieve was being able to use the + operator with NO extra memory usage compared to using strcat etc
const char * operator+(const char * first, const char * second);
You should not waste your time writing string classes - there's a reason people spent time writing them in the first place and it's naive to think they wrote them because they wanted to create big obfuscated and overheaded code that you could easily improve in a matter of hours.
For example your code has quadratic complexity for memory reallocations in the assignment operator - each assignment of a sting greater by 1 character will use a new memory block greater by 1 byte resulting in big memory fragmentation after a "few" assignments like this - you save a few bytes but potentialy lose megabytes to address space and memory page fragmentation.
Also designing this way you have no way of efficiently implementing the += operator as instead of just copying the appended string in most cases you will always need to copy the whole string - thus reaching quadratic complexity again in case you append small strings to one bigger one a few times.
Sorry but your idea looks to have great chances of becoming terrible to maintain and orders of magnitude less efficient then the typical string implementations like std::string.
Don't worry - this is true for practicaly all great ideas of "writing your own better version of a standard container" :)
struct myObj {
//...
char myVarChar;
};
This won't work. You either need a fixed size array, a pointer to char or use the struct hack. You won't be able to assign a pointer to this myVarChar.
so i'd like to create my own lightweight string class which has no extra overhead std::string has.
What extra overhead are you referring to? Have you tested and measured to see if std::string is really a bottleneck?
I think std::string is represented contiguously
Yes, mostly, the character buffer part. However, the following:
(int)length(char[])data
is not required by the standard. Translated: A string implementation need not use this particular layout of its data. And it may have additional data.
Now, your lightweight string class is frought with errors:
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?
};
Try something along the lines of the following:
/* 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;
};
Wow. What you're trying to do is a complete abuse of C++, would be totally compiler dependent if it worked, and would surely land you in TheDailyWTF some day.
The reason you're getting a segfault is probably because your operator= is reallocating the object to a different address, but you're not updating the myString pointer in main. I hesitate to even call it an object at this point, since no constructor was ever called.
I think what you're trying to do is make pString a smarter pointer to a string, but you're going about it all wrong. Let me take a crack at it.
#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() << "'";
}
Now I wouldn't use malloc but new/delete instead, but I left this as close to your original as possible.
You might think you are wasting the space of a pointer in your class, but you aren't - you're trading it for the pointer you previously kept in main. I hope this example makes it clear - the variables are the same size, and the amount of additional memory allocated by malloc/realloc is the same as well.
pString myString;
char * charString;
assert(sizeof(myString) == sizeof(charString));
P.S. I should point out that this code still needs a lot of work, it's full of holes. You need a constructor to initialize the pointer, and a destructor to free it when it's done, just for starters. You can do your own implementation of operator+, too.
You cannot change the size of an object/struct in either C or C++. Their sizes are fixed at compile time.
when they are represented in memory are objects C++ objects the same as C structs.
Strictly speaking, no. In general, yes. C++ classes and structs are identical in memory layout to C structs except:
Bit fields have different packing rules
Sizes are fixed at compile time
If there are any virtual functions, the compiler will add a vtable entry to the memory layout.
If the object inherits a base class, the new class' layout will be appended to the base class layout, including vtable, if any.
I don't think C++ allows overloading the + operator for the built in char * type. so i'd like to create my own lightweight string class which has no extra overhead std::string has. I think std::string is represented contiguously
You can create a operator+ overload for the char* type. Normal behavior is pointer arithmetic. std::string overloads operator+ to append char* data to the string. The string is stored in memory as a C string, plus additional information. The c_str() member function returns a pointer to the internal char array.
In your C example, you're relying on undefined behavior. Don't realloc like that. It can result in Bad Things - namely bizarre segfaults.
Your C++ example is also doing Bad Things in doing realloc(this). Instead, you should carry a char* and get a new char[] buffer to store the chars in instead of a realloc(). Behavior for such a realloc is undefined.
There is a lot a wrong with your class definition/usage. If you want to store a string you should use a pointer type, like char* a member, not an individual char. Using a single char means that only a single character of memory is allocated.
Another mistake is the allocation code where you do a realloc on this - you can potentially change the memory allocated, but not the value of this. You must assign the result to this to achieve this (this = (*pString)realloc(this, strlen(buff+1));) and that is really bad practice anyway. Much better to use realloc on a char* member.
Unfortunately C++ proper has no alternative for realloc or expand and you must instead use new and delete, doing any copying yourself.
Why do you write in C with classes, why don't use C++?
I do not think 'this' works the way you think it works.
Specifically, you cannot reallocate this to point to a larger buffer in a member function, because whatever called that member function still has a pointer to the old 'this'. Since it's not passed by reference there is no way that you can update it.
The obvious way around that is that your class should hold a pointer to the buffer and reallocate that. However, reimplementing a string class is a good way to give yourself lots of headaches down the line. A simple wrapper function would probably accomplish what you wanted (assuming "being able to use the + operator with NO extra memory usage compared to using strcat" is really what you wanted):
void concatenate(std::string& s, const char* c) {
s.reserve(s.size() + strlen(c));
s.append(c);
}
There's some probability that append may do that internally anyway though.
don't mind the lack of const correctness, as this is a mock up, but how about this:
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;
}
You are moving the "this" pointer. Thats not going to work.
I think what you really want is just a wrapper around a buffer.
#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 * 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 << "'";
}
Works When realloc doesn't re-assign the pointer i.e.
Address of this: 1049008
Address of this->c: 1049008
Address of this After: 1049008
Address of myString: 1049008 'testing'
Works, but when the the following happens it fails
Address of this: 1049008
Address of this->c: 1049008
Address of this After: 1049024
Address of myString: 1049008 ''
the obvious solution is to have
this = (pString*) newPoint;
But the compiler complains about an invalid lvalue in assignment. Does anyone the correct way to update this (just for completeness, i doubt i'll use the code since everyone seems to hate it). Thanks
If you want something that is basically the same as std::string except that it doesn't know how long the string is, you should learn how std::string works, what operator overloads it has, etc. and then mimic that, with just the differences you want.
There is unlikely to be any real point to this, however.
Regarding your latest update - you say you want a design in which general application code will be passing around naked pointers to heap objects. With no automatic cleanup.
This is, quite simply, a very bad idea.
What you want to do doesn't and cannot work in C++. What you are looking for is the C99-feature of flexible arrays. This works nice in C99 for two reasons, first you don't have build-in constructors and second you don't have inheritance (at least not as a language feature). If a class inherits from another the memory used by the subclass is packed by hind the memory of the parent class, but a flexible array needs to be at the end the structure/class.
class pString {
char txt[];
}
class otherString : pString { // This cannot work because now the
size_t len; // the flexible array is not at the
} // end
Take std::string it was written by experts of C++, I'm sure they didn't leaved out a "good trick" without a reason. If you still find out that they don't perform very well in your programm, use plain C strings instead, of course, they don't provide the sweet API, you want.
You can't realloc C++ objects. As others pointed out this is not really a pointer you can modify, there's no guarantee that it will be pointing to an area realloc has access.
One solution to concatenation is to implement a class hierarchy that will defer the real concatenation until it is needed.
Something like this
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;
}
So if you have
MyString a = "hello";
MyString b = " world";
MyString c = a + b;
Will turn into
MyString c = MyConcatString(a, b);
For more detail check "The C++ Programming language".
Other solution, is to wrap char* inside a struct, but you seem to no like this idea.
But whatever solution you will choose, objects in C++ can't be relocated.
If you want performance, you can write your class like this:
template<int max_size> class MyString
{
public:
size_t size;
char contents[max_size];
public:
MyString(const char* data);
};
Initialize max_size to an appropriate value under context. In this way the object can be created on stack, and no memory allocation is involved.
It is possible to create what you desired by overloading new operator:
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;
This code is a mess and RnR and others suggested is not advisable. But it works for what i want it to do:
#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);
}