Is it possible to create class String without using heap in C++? - c++

I would like to write me own class String which will have interface similar to std::string. String class shall not use dynamic memory allocation.
I need to have a c-tor:
String(char* ptrToFirstCharInTab, char* ptrToLastElementInTab);
And there should be tab which contains different (not know) number of element, so I do not know size while compiling.
In my opinion it's impossible, because if we do not know size of our array before compilation we can not create it without dynamic allocation - of course creating buffer for 500 char and then String class can be only 500 it' not my expections.
Do you have any idea? Maybe is any way to create buffor wchich I will shrink to fit? Thanks for help!

You asked:
Do you have any idea? Maybe is any way to create buffor wchich I will shrink to fit?
In theory, yes you can. You can use a pre-allocated buffer as your heap memory. However, you'll have to write your own code to manage that buffer. Doable but not something I would recommend.

You asked:
Is it possible to create class String without using heap in C++?
In fact, yes, it possible to dynamicly allocate memory on the stack by using _alloca or similiar platform dependent function. See this other answer for more details:
C++ How to allocate memory dynamically on stack?
I would recommend against it and be absolutely sure that was the best alternative before commencing.
Update:
I created an example with inlined constructer for demonstration purpose using gcc:
Compiler explorer Link:
https://godbolt.org/z/M1F5VD
Full code:
#include <alloca.h>
struct String {
__attribute__((always_inline)) inline String(size_t size) {
bytes= static_cast<char*>(alloca( size ));// alloca() memory gets allocated here
}
char* bytes;
};
int workWithString( )
{
//std::string teststr("test");
String mystrclass(1000);
mystrclass.bytes[0] = 'a';
mystrclass.bytes[1] = 0;
return 0;
} // alloca() memory only gets freed here
int main() {
return workWithString();
}

I'm a bit confused with your question. You want to have std:: string without a heap and without size restrictions. Sorry to bring this to you: you can't have infinite memory.
If you have an pool of memory you want to dedicate to strings without it being fixed size for each string, an allocator can do so.
The default allocator for the containers does new, however you can replace it without having to duplicate the internals of string.

Related

Determine the nature of parameter in runtime

I have a function
void fname(char* Ptr)
{
...
}
I want to know inside this function whether this pointer Ptr holds the address of dynamically allocated memory using new char[] or the address of locally allocated memory in the calling function. Is there any way I can determine that? I think <typeinfo> doesn't help here.
One way to do this is to have your own operator new functions and keep track of everything allocated so that you can just ask your allocation library if the address given is one it allocated. The custom allocator then just calls the standard one to actually do the allocation.
Another approach (messy and details highly OS dependent) may be to examine the process layout in virtual memory and hence determine which addresses refer to which areas of memory.
You can combine these ideas by actually managing your own memory pools. So if you get a single large chunk of system memory with known address bounds and use that for all new'd memory, you can just check that an address in is the given range to answer your question.
However: Any of these ideas is a lot of work and not appropriate if this problem is the only purpose in doing so.
Having said all that, if you do want to implement something, you will need to work carefully through all the ways that an address might be generated.
For example (and surely I've missed some):
Stack
Return from new
Inside something returned from new.
Was returned from new but already deleted (hopefully not, but that's why we need diagnostics)
statically allocated
static constant memory
command line arguments/ environment
code addresses.
Now, ignoring all that for a moment, and assuming this is for some debug purpose rather than system design, you might be able to try this kind of thing:
This is ugly, unreliable, not guaranteed by the standard, etc etc, but might work . . .
char* firstStack = 0;
bool isOnStack(const void* p)
{
char* check =(char*)p;
char * here = (char*)&check;
int a = firstStack - check;
int b = check - here;
return (a*b > 0);
}
void g(const char* p)
{
bool onStack = isOnStack(p);
std::cout << p << (onStack ? "" : " not" ) << " on stack " << std::endl;
}
void f()
{
char stuff[1024] = "Hello";
g(stuff);
}
void h()
{
char* nonsense = new char[1024];
strcpy(nonsense, "World");
g(nonsense);
delete [] nonsense;
}
int main()
{
int var = 0;
firstStack = (char*)&var;
f();
h();
}
Output:
Hello on stack
World not on stack
The short answer: no, you can't. You have no way of knowing whether Ptr is a pointer to a single char, the start of a statically allocated array, a pointer to a single dynamically allocated char, or the start of an array thereof.
If you really wanted to, you try an overload like so:
template <std::size_t N>
void fname(char Ptr[N])
{
// ...
}
which would match when passed a statically allocated array, whereas the first version would be picked when dealing with dynamically allocated memory or a pointer to a single char.
(But note that function overloading rules are a bit complicated in the presence of templates -- in particular, a non-template function is preferred if it matches. So you might need to make the original function take a "dummy" template parameter if you go for this approach.)
In vc++ there is an assertion _CrtIsMemoryBlock (http://msdn.microsoft.com/en-us/library/ww5t02fa.aspx#BKMK_CRT_assertions) that can be used to check if a pointer was allocated from the heap. This will only work when a debug heap is being used but this is fine if you are just wanting to add some 'debug only' assertions. This method has worked well for me in the past under Windows.
For Linux however I know of no such equivalent.
Alternatively you could use an inline assembler block to try to determine the if it is a stack address or not. This would be hardware dependent as it would rely heavily not only on the processor type but also on the memory model being used (flat address model vs segmented etc). Its probably best to avoid this type of approach.

C++ array and vector dynamic item size

I guess I'm still not understanding the limitations of C++ containers and arrays. According to this post and this It is impossible to store items of dynamic size in an STL vector.
However with the following code I can dynamically re-size an element of a vector with the results one would expect if it was ok to have items of varying and changing size in a vector.
string test = "TEST";
vector<string> studentsV;
for (int i = 0; i < 5; ++i)
{
studentsV.push_back(test);
}
studentsV[2].resize(100);
for (string s : studentsV)
{
cout << s << "end" << endl;
}
Result:
TESTend
TESTend
TEST
end
TESTend
TESTend
I can re-size the string element to any size, and it works fine. I can also do the same with a regular C-style array. So, what is the difference between the above posts and what I am doing, and can you give an example of what "dynamic item size" really means, because apparently I am not understanding.
A std::string uses dynamic memory to increase the size of the string being stored. This is not what those articles are talking about.
What they mean, is that sizeof(std::string) is constant. The actual object representing a std::string will always have the same size, but it might do additional allocations in another part of memory.
A std::vector is really just a friendly wrapper around a dynamically-sized array. The definition of an array in C or C++ is a contiguous block of memory where all elements are of equal size.
can you give an example of what "dynamic item size" really means, because apparently I am not understanding.
This is the core of your question.
Namely: if all C++ classes (even ones that manage dynamic memory as part of their implementations) have a fixed and known footprint size via sizeof()...just what sort of thing is it that you can't put in a std::vector?
Since something like a std::string and a std::bitset are classes of different sizes, you couldn't have a vector of [string string bitset string bitset string]. But the type system already wouldn't let you do that. So that can't be what they're talking about.
They're just saying there's no hook for supporting structures like this from the C world:
struct packetheader {
int id;
int filename_len;
};
struct packet {
struct packetheader h;
char filename[1];
};
You couldn't make a std::vector<packet> and expect to find some parameter to push_back letting you specify a per-item size. You'd lose any data you'd allocated outside of the structure boundary.
So to use something like that, you'd have to do std::vector<packet*> and store pointers.
The size of std::string is not dynamic. std::string is probably implemented with a pointer to a dynamically allocated memory. This makes sizeof(std::string) static and possibly different from the size of the actual string.

How to find the size of the memory deallocated

I am writing a big code and I prepared a memory class in order to create and grow different types of arrays safely. In this class I keep track of the size of memory that allocated using sizeof when allocating a new pointer. However, I do not know how to keep track of the memory allocating.
Let me put my question in another way. For example suppose we allocate a new array at some point in the code:
double* array=new double[size];
and some place else we want to deallocate the memory without knowing the size, normally we use
delete [] array;
delete operator automatically frees the memory of array, is there any way to determine how many bytes does it free (supposing that we don't keep track of size)?
In general, the answer is no, because memory managers hide that kind of implementation-dependent information from you. Also, C++ doesn't provide any standard way of tracking how much memory is actually used/freed. There might be functions specific to a certain platform/operating system, but nothing that is 100% portable.
use a std::vector instead and when you delete it you can call this beforehand to find out how much was cleared: vec.capacity() * sizeof(OBJECT) will give you the amount of bytes stored in the vector.
To keep track of allocated memory you need to implement manuelly some kind of counting mechanism, for example with a static (private) member which counts the allocated bytes.
If you want to have full control over memory allocation and deallocations you should use amemory pool.
Home grown memory pools are fast, safe and relatively easy to implement - unless you want fancy stuff. Implementing such a mechanism will provide you will all kinds of information such as memory leaks too. Calculating the memory freed is also a breeze because the linked list holds the total memory allocated.
Click the big friendly button to dive in.
I realize another answer was already accepted, but here is how you write your own allocators if you wanted to very simply track memory arrays:
#include <map>
#include <iostream>
using namespace std;
map<void*,size_t> memmap; //put this as a global variable in an implementation file, and extern it in the header file.
class MyManagedClass{
public:
MyManagedClass(){}
void* operator new[](size_t sz){
void* out = operator new(sz*sizeof(MyManagedClass));
for(size_t i=0; i<sz; ++i)
*((MyManagedClass*)out+sz)=MyManagedClass::MyManagedClass();
memmap[out] = sz;
return out;
}
void operator delete[](void* t){
cout << "Freed units: " << memmap[t] << endl;
memmap.erase(t);
delete[] t;
}
};
int main(){
MyManagedClass* ip = new MyManagedClass[10];
delete[] ip;
system("pause");
}
I should mention that this is a scrappy way to do it, and you could probably make it nicer/generic with templates and a more thought out memory design lol.

Stack overflow when declare 2 array

When I run my program with 1 array, like this:
int a[430][430];
int i, j, i_r0, j_r0;
double c, param1, param2;
int w_far = 0,h_far = 0;
char* magic_num1 = "";
it's good!
But, when I write:
int a[430][430];
int i, j, i_r0, j_r0;
int nicky[430][430]; // Added line
double c, param1, param2;
int w_far = 0,h_far = 0;
char* magic_num1 = "";
the program not run with the error: "stack overflow"!
I don't know how to solve it!
You need to either increase the stack space (how that is done depends on your platform), or you need to allocate the array from the heap, or even better, use std::vector instead of an array.
You're trying to allocate ~1.48 MB of stuff on the stack1, on your system (and not only on it) that's too much.
In general, the stack is not made for keeping big objects, you should put them in the heap instead; use dynamic allocation with new or std::vector, or, even better suited in your case, boost::multi_array.
1. Assuming 32 bit ints.
A proper solution is to use heap, but also note that you'll likely find that changing to:
short a[430][430];
short nicky[430][430]; // Added line
fixes the overflow, depending on your platform. So if 'short', or 'unsigned short' is big enough, this might be an option.
In fact, even when using the heap, consider carefully the array type to reduce memory footprint for a large array.
Local variables are allocated to "stack", which is a storage space used to several purposes and limited to a certain size.
Usually you can declare variables up to several kilobytes, but when you want to use more memory, usually suggested to use "heap", which can be allocated by new operator or std::vector.
std::vector is an alternate for traditional arrays, and its data is safely stored in heap.
To avoid stack overflow, allocate the arrays in the heap.
If one uses C, then allocating an array of size n in the heap can be done by e.g.
int* A = (int*) malloc(n*sizeof(int));
But you must remeber to free that memory when no longer needed with
free(A);
to avoid memory leak.
Equivalently in C++:
int* A = new int[n];
and free with
delete [] A;
This site was helpful.

C++ string manipulation

My lack of C++ experience, or rather my early learning in garbage collected languages is really stinging me at the moment and I have a problem working with strings in C++.
To make it very clear, using std::string or equlivents is not an option - this is char* 's all the way.
So: what I need to do is very simple and basically boils down to concatenating strings. At runtime I have 2 classes.
One class contains "type" information in the form of a base filename.
in the header:
char* mBaseName;
and later, in the .cpp it is loaded with info passed in from elsewhere.
mBaseName = attributes->BaseName;
The 2nd class provides version information in the form of a suffix to the base file name, it's a static class and implemented like this at present:
static const char* const suffixes[] = {"Version1", "Version", "Version3"}; //etc.
static char* GetSuffix()
{
int i = 0;
//perform checks on some data structures
i = somevalue;
return suffixes[i];
}
Then, at runtime the base class creates the filename it needs:
void LoadStuff()
{
char* suffix = GetSuffix();
char* nameToUse = new char[50];
sprintf(nameToUse, "%s%s",mBaseName,suffix);
LoadAndSetupData(nameToUse);
}
And you can see the problem immediately. nameToUse never gets deleted, memory leak.
The suffixes are a fixed list, but the basefilenames are arbitrary. The name that is created needs to persist beyond the end of "LoadStuff()" as it's not clear when if and how it is used subsequently.
I am probably worrying too much, or being very stupid, but similar code to LoadStuff() happens in other places too, so it needs solving. It's frustrating as I don't quite know enough about the way things work to see a safe and "un-hacky" solution. In C# I'd just write:
LoadAndSetupData(mBaseName + GetSuffix());
and wouldn't need to worry.
Any comments, suggestions, or advice much appreciated.
Update
The issue with the code I am calling LoadAndSetupData() is that, at some point it probably does copy the filename and keep it locally, but the actual instantiation is asynchranous, LoadAndSetupData actually puts things into a queue, and at that point at least, it expects that the string passed in still exists.
I do not control this code so I can't update it's function.
Seeing now that the issue is how to clean up the string that you created and passed to LoadAndSetUpData()
I am assuming that:
LoadAndSetUpData() does not make its own copy
You can't change LoadAndSetUpData() to do that
You need the string to still exist for some time after LoadAndSetupData() returns
Here are suggestions:
Can you make your own queue objects to be called? Are they guaranteed to be called after the ones that use your string. If so, create cleanup queue events with the same string that call delete[] on them
Is there a maximum number you can count on. If you created a large array of strings, could you use them in a cycle and be assured that when you got back to the beginning, it would be ok to reuse that string
Is there an amount of time you can count on? If so, register them for deletion somewhere and check that after some time.
The best thing would be for functions that take char* to take ownership or copy. Shared ownership is the hardest thing to do without reference counting or garbage collection.
EDIT: This answer doesn't address his problem completely -- I made other suggestions here:
C++ string manipulation
His problem is that he needs to extend the scope of the char* he created to outside the function, and until an asynchronous job is finished.
Original Answer:
In C++, if I can't use the standard library or Boost, I still have a class like this:
template<class T>
class ArrayGuard {
public:
ArrayGuard(T* ptr) { _ptr = ptr; }
~ArrayGuard() { delete[] _ptr; }
private:
T* _ptr;
ArrayGuard(const ArrayGuard&);
ArrayGuard& operator=(const ArrayGuard&);
}
You use it like:
char* buffer = new char[50];
ArrayGuard<char *> bufferGuard(buffer);
The buffer will be deleted at the end of the scope (on return or throw).
For just simple array deleting for dynamic sized arrays that I want to be treated like a static sized array that gets released at the end of the scope.
Keep it simple -- if you need fancier smart pointers, use Boost.
This is useful if the 50 in your example is variable.
The thing to remember with C++ memory management is ownership. If the LoadAndSetupData data is not going to take ownership of the string, then it's still your responsibility. Since you can't delete it immediately (because of the asynchronicity issue), you're going to have to hold on to those pointers until such time as you know you can delete them.
Maintain a pool of strings that you have created:
If you have some point in time where you know that the queue has been completely dealt with, you can simply delete all the strings in the pool.
If you know that all strings created after a certain point in time have been dealt with, then keep track of when the strings were created, and you can delete that subset. - If you can somehow find out when an individual string has been dealt with, then just delete that string.
class StringPool
{
struct StringReference {
char *buffer;
time_t created;
} *Pool;
size_t PoolSize;
size_t Allocated;
static const size_t INITIAL_SIZE = 100;
void GrowBuffer()
{
StringReference *newPool = new StringReference[PoolSize * 2];
for (size_t i = 0; i < Allocated; ++i)
newPool[i] = Pool[i];
StringReference *oldPool = Pool;
Pool = newPool;
delete[] oldPool;
}
public:
StringPool() : Pool(new StringReference[INITIAL_SIZE]), PoolSize(INITIAL_SIZE)
{
}
~StringPool()
{
ClearPool();
delete[] Pool;
}
char *GetBuffer(size_t size)
{
if (Allocated == PoolSize)
GrowBuffer();
Pool[Allocated].buffer = new char[size];
Pool[Allocated].buffer = time(NULL);
++Allocated;
}
void ClearPool()
{
for (size_t i = 0; i < Allocated; ++i)
delete[] Pool[i].buffer;
Allocated = 0;
}
void ClearBefore(time_t knownCleared)
{
size_t newAllocated = 0;
for (size_t i = 0; i < Allocated; ++i)
{
if (Pool[i].created < knownCleared)
{
delete[] Pool[i].buffer;
}
else
{
Pool[newAllocated] = Pool[i];
++newAllocated;
}
}
Allocated = newAllocated;
}
// This compares pointers, not strings!
void ReleaseBuffer(char *knownCleared)
{
size_t newAllocated = 0;
for (size_t i = 0; i < Allocated; ++i)
{
if (Pool[i].buffer == knownCleared)
{
delete[] Pool[i].buffer;
}
else
{
Pool[newAllocated] = Pool[i];
++newAllocated;
}
}
Allocated = newAllocated;
}
};
Since std::string is not an option, for whatever reason, have you looked into smart pointers? See boost
But I can only encourage you to use std::string.
Christian
If you must use char*'s, then LoadAndSetupData() should explicitly document who owns the memory for the char* after the call. You can do one of two things:
Copy the string. This is probably the simplest thing. LoadAndSetupData copies the string into some internal buffer, and the caller is always responsible for the memory.
Transfer ownership. LoadAndSetupData() documents that it will be responsible for eventually freeing the memory for the char*. The caller doesn't need to worry about freeing the memory.
I generally prefer safe copying as in #1, because the allocator of the string is also responsible for freeing it. If you go with #2, the allocator has to remember NOT to free things, and memory management happens in two places, which I find harder to maintain. In either case, it's a matter of explicitly documenting the policy so that the caller knows what to expect.
If you go with #1, take a look at Lou Franco's answer to see how you might allocate a char[] in an exception-safe, sure to be freed way using a guard class. Note that you can't (safely) use std::auto_ptr for arrays.
Since you need nameToUse to still exist after the function, you are stuck using new, what I would do is return a pointer to it, so the caller can "delete" it at a later time when it is no longer needed.
char * LoadStuff()
{
char* suffix = GetSuffix();
char* nameToUse = new char[50];
sprintf("%s%s",mBaseName,suffix);
LoadAndSetupData(nameToUse);
return nameToUse;
}
then:
char *name = LoadStuff();
// do whatever you need to do:
delete [] name;
There is no need to allocate on heap in this case. And always use snprintf:
char nameToUse[50];
snprintf(nameToUse, sizeof(nameToUse), "%s%s",mBaseName,suffix);
Where exactly nameToUse is used beyond the scope of LoadStuff? If someone needs it after LoadStuff it needs to pass it, along with the responisbility for memory deallocation
If you would have done it in c# as you suggested
LoadAndSetupData(mBaseName + GetSuffix());
then nothing would reference LoadAndSetupData's parameter, therefore you can safely change it to
char nameToUse[50];
as Martin suggested.
You're going to have to manage the lifetime of the memory you allocate for nameToUse. Wrapping it up in a class such as std::string makes your life a bit simpler.
I guess this is a minor outrage, but since I can't think of any better solution to your problem, I'll point out another potential problem. You need to be very careful to check the size of the buffer you're writing into when copying or concatenating strings. Functions such as strcat, strcpy and sprintf can easily overwrite the end of their target buffers, leading to spurious runtime errors and security vulnerabilities.
Apologies, my own experience is mostly on the Windows platform, where they introduced "safe" versions of these functions, called strcat_s, strcpy_s, and sprintf_s. The same goes for all their many related functions.
First: Why do you need for the allocated string to persist beyond the end of LoadStuff()? Is there a way you can refactor to remove that requirement.
Since C++ doesn't provide a straightforward way to do this kind of stuff, most programming environments use a set of guidelines about pointers to prevent delete/free problems. Since things can only be allocated/freed once, it needs to be very clear who "owns" the pointer. Some sample guidelines:
1) Usually the person that allocates the string is the owner, and is also responsible for freeing the string.
2) If you need to free in a different function/class than you allocated in, there must be an explicit hand-off of ownership to another class/function.
3) Unless explicitly stated otherwise, pointers (including strings) belong to the caller. A function, constructor, etc. cannot assume that the string pointer it gets will persist beyond the end of the function call. If they need a persistent copy of the pointer, they should make a local copy with strdup().
What this boils down to in your specific case is that LoadStuff() should delete[] nameToUse, and the function that it calls should make a local copy.
One alternate solution: if nameToUse is going to be passed lots of places and needs to persist for the lifetime of the program, you could make it a global variable. (This saves the trouble of making lots of copies of it.) If you don't want to pollute your global namespace, you could just declare it static local to the function:
static char *nameToUse = new char[50];
Thankyou everyone for your answers. I have not selected one as "the answer" as there isn't a concrete solution to this problem and the best discussions on it are all upvoted be me and others anyway.
Your suggestions are all good, and you have been very patient with the clunkiness of my question. As I am sure you can see, this is a simplification of a more complicated problem and there is a lot more going on which is connected with the example I gave, hence the way that bits of it may not have entirely made sense.
For your interest I have decided to "cheat" my way out of the difficulty for now. I said that the base names were arbitrary, but this isn't quite true. In fact they are a limited set of names too, just a limited set that could change at some point, so I was attempting to solve a more general problem.
For now I will extend the "static" solution to suffixes and build a table of possible names. This is very "hacky", but will work and moreover avoids refactoring a large amount of complex code which I am not able to.
Feedback has been fantastic, many thanks.
You can combine some of the ideas here.
Depending on how you have modularized your application, there may be a method (main?) whose execution determines the scope in which nameToUse is definable as a fixed size local variable. You can pass the pointer (&nameToUse[0] or simply nameToUse) to those other methods that need to fill it (so pass the size too) or use it, knowing that the storage will disappear when the function having the local variable exits or your program terminates by any other means.
There is little difference between this and using dynamic allocation and deletion (since the pointer holding the location will have to be managed more-or-less the same way). The local allocation is more direct in many cases and is very inexpensive when there is no problem with associating the maximum-required lifetime with the duration of a particular function's execution.
I'm not totally clear on where LoadAndSetupData is defined, but it looks like it's keeping its own copy of the string. So then you should delete your locally allocated copy after the call to LoadAndSetupData and let it manage its own copy.
Or, make sure LoadAndSetupData cleans up the allocated char[] that you give it.
My preference would be to let the other function keep its own copy and manage it so that you don't allocate an object for another class.
Edit: since you use new with a fixed size [50], you might as well make it local as has been suggested and the let LoadAndSetupData make its own copy.