Strictly speaking, your question has nothing to do with the STL, even if you accept "STL" as a synonym for the correct "containers, iterators and algorithms of the C++ standard library". std::string
was at one point of is history made to appear like a container (a container of characters, that is), but it is generally used in quite a different fashion than "real" container classes like std::vector
or std::set
.
Anyway,
Why doesnt mystr string get "haha"
Because you don't use references. x
modifies a copy of the argument; likewise, string k = (obj.k)
creates a copy of the string. Here is the code with references:
void x ( s &obj ) {
string &k = (obj.k) ;
k += "haha" ;
}
a) How and when do STL objects get allocated?
The container object itself is allocated as you define it. How it allocates memory internally is defined by its allocator template parameter, by default std::allocator
. You don't really want to know the internals of std::allocator
- it almost always does the right thing. And I don't think your question is about internal allocations, anyway.
I supposed mystr is on a stack and must be accessible to all functions called from main()
Yes.
b) What if I need to store STL objects in a old fashioned Linked list
which needs "void*".
Use std::list<void*>
.
But you don't have to do this. Use std::list<std::string>
and you likely won't need pointers in your code at all.
As for your further code examples:
std::string mystr ("mystring.." );
MyList.Add((void*)&mystr) ;
fun(MyList) ;
Can the function fun, now use and modify mystr by accessing MyList ?
Yes. However, the code has two problems. The smaller one is (void*)&mystr
. Generally, you should avoid C-style casts but use one of static_cast
, reinterpret_cast
, const_cast
or dynamic_cast
, depending on which conversion you need. And in this piece of code, you don't need a cast at all, anyway.
The bigger problem is adding the address of a local variable to something which looks like it expects dynamically allocated objects. If you return MyList
from a function, mystr
will be destroyed and the copied list will contain a pointer to a dead object, eventually leading to undefined results.
In order to solve this, you have to learn more about new
, delete
and, possibly, smart pointers. This is beyond the scope of a simple answer, and the outcome would probably still be worse than std::list<std::string>
.
The issue is can I declare a class to keep a reference of mystr?
Yes, but you should generally avoid it, because it easily leads to dangling references, i.e. references to dead objects, for the reasons explained above.
class MyList {
string& mStr ;
...
};
MyList::MyList ( string& mystr ) {
mStr = mystr ;
}
Is that constructor valid ?
No, it won't compile. You'd need to use an initialisation list:
MyList::MyList ( string& mystr ) : myStr(mystr) {}
I can only repeat my recommendation from above. Use std::list<std::string>
.