Is there any way to create an std::string inside a class but store it outside of the class (but not in the heap). So even if the object that created the string gets destructed, another object that will have the address of the string will be able to access the string. I have managed to do it by declaring the string as new but I don't want to store it in the heap.
Here is a simple example of what I want to do (but I want to do it without declaring the string as new):
Is there any way to create an std::string inside a class but store it outside of the class (but not in the heap).
Why?
but I don't want to store it in the heap.
Why?
All of that sounds rather abstruse. Explain what you're trying to accomplish instead of what you think needs to be done in order to accomplish your goal.
Ok, you are right. I was trying to create a memory efficiency program. The class StringHolder would be responsible of holding a pointer to a string. If there is another StringHolder object that holds pointer to an identical string, then the identical string should be deleted and the second object should point to the first string (if it is identical). This is pretty much what my program should do. This is my code:
#include <iostream>
#include <cstring>
#include <string>
#include <map>
class StringManager
{
public:
StringManager() {}
~StringManager()
{
pointer_count.clear();
}
//Adds or increments a certain element in the map.
std::string* AddString(std::string* a_Data)
{
if (pointer_count.empty())
{
pointer_count.insert(std::pair<std::string*, int>(a_Data, 1));
}
else
{
std::string data = *a_Data;
int count = 0;
for (Map_Type::iterator iter = pointer_count.begin(); iter != pointer_count.end(); ++iter)
{
count++;
if (data == *(iter->first))
{
delete a_Data;
a_Data = iter->first;
++iter->second;
break;
}
}
if (count == pointer_count.size())
{
pointer_count.insert(std::pair<std::string*, int>(a_Data, 1));
}
}
return a_Data;
}
//Deletes or decrements a certain map element.
void DeleteString(std::string* a_Data)
{
for (Map_Type::iterator iter = pointer_count.begin(); iter != pointer_count.end(); ++iter)
{
if (iter->first == a_Data)
{
if (iter->second == 1)
{
delete a_Data;
pointer_count.erase(iter);
}
else
{
--iter->second;
}
}
}
}
void PrintString()
{
for (Map_Type::iterator iter = pointer_count.begin(); iter != pointer_count.end(); ++iter)
{
std::cout << "String " << *iter->first << " has : " << iter->second << " pointer(s), the address is: " << iter->first << std::endl;
}
}
private:
typedef std::map<std::string*, int> Map_Type;
Map_Type pointer_count; //A map that keeps track of the pointers.
};
class StringHolder
{
public:
StringHolder(std::string a_Data)
{
m_Data = new std::string (a_Data);
m_Data = g_StrMgr.AddString(m_Data);
}
voidoperator+=(std::string rhs)
{
std::string* newStr = new std::string (*m_Data);
(*newStr).append(rhs);
g_StrMgr.AddString(newStr);
g_StrMgr.DeleteString(m_Data);
m_Data = newStr;
}
~StringHolder()
{
g_StrMgr.DeleteString(m_Data);
}
void Print()
{
g_StrMgr.PrintString();
std::cout << "\n" << std::endl;
}
private:
std::string* m_Data;
static StringManager g_StrMgr;
};//class StringHolder
StringManager StringHolder::g_StrMgr;
int main()
{
StringHolder a("anna");
a.Print();
StringHolder b("anna");
b.Print();
StringHolder c("maria");
c.Print();
b += "Oleg";
b.Print();
StringHolder d("anna");
d.Print();
StringHolder e("anna");
e.Print();
StringHolder h("maria");
h.Print();
StringHolder i("annamaria");
i.Print();
return 0;
}
It works perfectly fine, but my tutor asked me "Is it really necessary to allocate memory on the heap when we are using std::string?" and that confused me.
Right, now it's getting clearer.
Your tutor means that you shouldn't use pointers to std::string and just use std::string directly.
This would greatly simplify your program.
Among other things, it would allow you to reduce AddString to the following:
Yea you are right, but I became stubborn and wanted to finish it with the pointers, but I think I will have to change it after all.
So you think there is not a simple way to finish it with the pointers?
To me, your question reads as "is there a simple way to do it the complicated way?".
You could simplify it to some extent by using a custom comparison function that compares the strings instead of the pointers themselves.