std::string memory.

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):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>


class StringKeeper
{
public:
	StringKeeper(std::string a_Data)
		{
			m_Data = new std::string (a_Data);
		}
	~StringKeeper()
		{
			delete m_Data;
		}
	void PrintString()
		{
			std::cout << *m_Data << std::endl;
		}
protected:
	std::string* m_Data;
};
int main()
{
StringKeeper one("Cat");
one.PrintString();
return 0;
}
I forgot to say that I should not create the string inside main either.
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.
Last edited on
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#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);
		}

		void operator+=(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:

1
2
3
4
void AddString(std::string a_Data)
{
    pointer_count[a_Data]++;
}
Last edited on
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.
Thank you very much for your help!
Topic archived. No new replies allowed.