I'm a beginner in C++ and ran into a problem. Please see my code below. The issue is described in the inline comments.
#include<iostream>
#include<tuple>
#include<vector>
// #include "test.hpp"
using namespace std;
vector<string*> test();
int main() {
vector<string*> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: random undefined behavior
//I want this to output "s"
}
vector<string*> test() {
vector<string*> ret;
string str = "t";
ret.push_back(&str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "t"
str[0] = 's';
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *ret.back() << endl; //Outputs: "s"
return ret;
}
Basically I want to have it so that I can declare an object in a function body, add it to a vector, and be able to modify the object again later in the function (any time in the future) and be able to see these changes anywhere I have this vector. This can be easily done in Java, but I'm having trouble doing it in C++.
Objects declared with automatic lifetime always cease to exist when the scope in which they were created is left.
If you want an object to survive beyond the scope in which it was created you must create the object with dynamic lifetime, using (directly or indirectly) the new keyword. Remember though, C++ has no garbage collector, so for every use of new you must delete the created object when you're done with it. The best way to do that is to use some form of smart pointer, like std::unique_ptr or std::shared_ptr (which to use depends on your exact situation):
std::vector<std::unique_ptr<std::string>> test() {
std::vector<std::unique_ptr<std::string>> ret;
std::unique_ptr<std::string> str = std::make_unique<std::string>("t");
ret.push_back(std::move(str));
//...
return ret;
}
(std::make_unique uses new to create a new object and returns a std::unique_ptr to it)
In this particular case there's really no advantage to storing pointers to strings in your vector though. A std::string object is essentially a smart pointer to an array of characters, so you can just store the objects directly:
std::vector<std::string> test() {
std::vector<std::string> ret;
ret.push_back("t");
//...
return ret;
}
Stop using pointers. They have their place in C++ but not in the code you've posted.
The specific problem is this:
string str = "t";
ret.push_back(&str);
You are storing a pointer to a function-local std::string object. At the end of the function the std::string goes out of scope and is destroyed, leaving you with a dangling pointer and undefined behavior.
Change vector<string*> ret; to vector<string> ret;. Store objects instead of pointers, value semantics are easier to reason about. Standard library containers and strings are designed to do the right thing and make all of this simple.
You want to change this:
string str = "t";
ret.push_back(&str);
To this:
string* str = new string("t");
ret.push_back(str);
The problem is that in your original example your string gets destroyed when you exit test(), meaning that its memory address now points at nothing. To avoid this, you want to allocate str on the heap by using a pointer so that the memory isn't cleaned up after you exit test().
Just remember that whenever you manually allocate memory in C++, you must deallocate it to avoid memory leaks:
for (string* i : ret) {
delete i;
}
You are pushing back the address of a local variable. When the variable goes out of scope, that memory address is freed.
You can use unique_ptr or shared_ptr instead, something like this:
#include<iostream>
#include<tuple>
#include<vector>
#include<memory>
// #include "test.hpp"
using namespace std;
vector<std::shared_ptr<string>> test();
int main() {
vector<std::shared_ptr<string>> ret = test();
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
}
vector<std::shared_ptr<string>> test() {
vector<std::shared_ptr<string>> ret;
const auto str = std::make_shared<string>("t");
ret.push_back(str);
cout << ret.back() << endl; //Outputs: Memory of String str
cout << *(ret.back()) << endl; //Outputs: "t"
return ret;
}
Related
Is calling this function creating a memory leak?
#include <iostream>
std::string somefunc()
{
std::string somestrng;
somestrng = "Fred";
return somestrng;
}
int main()
{
std::cout << "Hello World!\n";
std::string receiver = somefunc();
std::cout << "-->" << receiver.data() << "<--" << std::endl;
}
I've read about "value semantics" but I can't envision it.
No, there is no memory leak in the shown program.
In general, memory leaks happen when you allocate dynamic memory, and neglect to deallocate that memory.
You don't directly allocate any dynamic memory in the example program. std::string may potentially allocate some dynamic memory, but it will also deallocate it. For future learning, I would recommend studying the RAII pattern, which the string class follows.
I'm newbee about c++ and I'm having trouble with destructors. When i create an object and push to a vector that holds class, i can see variable "_path" is initialized. But after i try to reach the variable, i see object calls decontsuctor and i cant see the variable.
Here is the code:
#include <iostream>
#include <vector>
#include <string>
#include "ClassA.h"
A returnA(const char* char_a)
{
return A(char_a);
}
int main() {
std::vector<A> vectorA;
for (int i = 0; i < 10; i++)
{
std::string s = std::to_string(i);
vectorA.emplace_back(returnA(s.c_str()));
}
std::cout << "-------" << std::endl;
for (int i = 0; i < vectorA.size(); i++)
{
vectorA[i].getPath();
}
return 0;
}
class A
{
public:
const char* _path;
A(const char* path);
~A();
void getPath();
};
A::A(const char* path)
{
_path = path;
std::cout << "Obj is constructed! " << _path << std::endl;
}
A::~A()
{
std::cout << "Obj is deconstructed! ";
std::cout << _path << std::endl;
}
inline void A::getPath()
{
std::cout << _path << std::endl;
}
How can i prevent objects not deconstruct themselves and reach their variables without dynamic allocation?
std::string s = std::to_string(i);
vectorA.emplace_back(returnA(s.c_str()));
std::string's c_str() method returns a pointer to std::string's internal buffer that's no longer valid when the std::string gets changed in any way.
This std::string gets destroyed at the end of this for loop, and that certainly meets all "any way" requirements. This is how all objects work in C++. This std::string's gets declared inside a for loop, and it gets destroyed as soon as the end of the loop ends and it iterates again (or stops).
At this point accessing this pointer becomes undefined behavior, this is what you're seeing.
As far as destructor calls: this is completely unrelated, this is simply how vectors work. When objects get added to a vector they get moved or copied into the vector itself. Additionally, a vector resizes itself, as it grows, because that's what a vector is all about. If you add an object to a vector, and then destroy the original object you'll, obviously, see the destructor getting called:
vectorA.emplace_back(returnA(s.c_str()));
The temporary object returned from returnA gets copied/moved into the vector, here. Then this temporary object gets destroyed, and this is the destructor call you're seeing. But the vector continues to hold its copy of the emplaced object, safe and sound.
The simplest way to fix your undefined behavior is to simply replace the const char * member of your class with its own std::string (and just the parameter to the constructor accordingly. This is what std::strings for: as you move or copy them around they'll take care of all the housekeeping for you.
This, of course, won't change the destructor behavior or invocation, it does not affect that.
# include <iostream>
# include <string>
using std::string;
using std::cout;
using std::endl;
string func() {
string abc = "some string";
return abc;
}
void func1(string s) {
cout << "I got this: " << s << endl;
}
int main() {
func1(func());
}
This gives:
$ ./a.out
I got this: some string
How/why does this code work ? I wonder because abc went out of scope and got destroyed as soon as the call to func() completed. So a copy of abc cannot be/should not be available in variable s in function func1 Is this understanding correct ?
The return value is copied from the local variable, effectively creating a new string object.
However, RVO (returned value optimization) should eliminate this step.
Try single stepping your code in a debugger. You should see the std::string copy constructor called for the return line. Be sure to compile with debug enabled and optimizers off.
Your code is essentially asking:
"Call func1, and in order for func1 to work I have to receive a string which we can use by calling the copy constructor on that string. The parameter for func1 we want to come from the return value of func (which we know has to be a string since its explicitly defined".
abc goes out of scope only after the copy constructor is called on the return value of func() which passes the value of the string. In theory you could have written it passed by reference or constant reference:
void func1(string& s) {
cout << "I got this: " << s << endl;
}
Which allows func1 to directly access the string in memory through a pointer (and also change it, if your code was meant to.)
void func1(string const& s) {
cout << "I got this: " << s << endl;
}
Which provides a constant reference to the string from func(). This ensures that you get a pointer to the data and that you won't change its contents. Typically passing data by constant reference (const&) is desirable because it's very fast and keeps your code from accidentally changing data that it shouldn't.
You really only need to pass by value if you're going to manipulate the data once you pass it to the new function, saving you the resources of creating another new container to handle the manipulation:
void func1(string s) {
s += " some extra stuff to add to the end of the string"; //append some new data
cout << "I got this: " << s << endl;
}
A sample where std::string is corrupted cause the scope with its value ends:
#include <bits/stdc++.h>
const int StackSize = 2137;
char stack[StackSize];
template <typename Type>
Type& push(Type value) {
char *ptr = (char*)&value;
std::copy_n(ptr, sizeof(Type), stack);
return *(Type*)stack;
}
template <typename Type>
Type& create(Type value) {
auto &var = push<Type>(value);
std::cout << "Should Be: " << var << '\n';
return var;
}
int main() {
auto &x = create<std::string>("Hello");
std::cout << "Is: " << x << '\n';
}
When I change the function push to receive a pointer the output is correct, but currently it's "b"
I understand that std::string has a pointer to a c-string and the output is different because argument of the function push is destroyed when the scope ends.
But why when I pass a pointer to push, the output is still correct? The c-string should be destroyed after create ends.
Because you are trying to store non-trivial object (std::string) in the buffer of chars via C-like memcpy/copy_n.
Obviously that fails, because you just copy it byte-by-byte there, so its data pointer points to the same location as a temporary value string, and then, when the data is freed by value destructor (at least if your compiler doesn't do SSO), you invoke UB trying to access it through your stack.
I'm not clear how the code that "works" for you looks, but I guess it just avoids the problem by allocating string on heap and not deleting it.
Consider studying how it's done in C++ (i.e. placement new).
I know that a map destructor calls each of the contained element's destructors. What happens for a
map<char*,char*> ?
I cannot see where this code is in /usr/include/c++/4.4
EDIT:
I should have said
map<const char*, const char*, ltstr>
like in
http://www.sgi.com/tech/stl/Map.html
When a map<char*,char*> is destroyed, so are all of the elements it contains. Each element's destructor is called, if it is of class type.
However, keep in mind exactly what is contained in your map above. It isn't strings, as you might expect -- it's just pointers to strings. The strings themselves aren't destroyed. Only the pointers are. delete is never called on the pointers.
Case in point:
map<char*, char*> strings;
char* key = new char[10];
char* value = new char[256];
/* ... */
strings.insert(key,value);
In the above, since delete is never called on the pointers created by the calls to new, this memory will leak when strings goes out of scope.
This is a good illustration of why you should avoid using raw pointers, new and delete. In your case, map<string,string> would probably be a better choice.
EDIT:
As #sbi mentioned in the comments, another reason why you would want map<string,string> over map<char*,char*> is because with map<string,string> keys are compared by-value, rather than by-pointer-value.
Consider:
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main()
{
static const char MyKey[] = "foo";
const char bar[] = "bar";
typedef map<const char*,const char*> Strings;
Strings strings;
strings.insert(make_pair(MyKey,bar));
string ss = "foo";
Strings::const_iterator it = strings.find(ss.c_str());
if( it == strings.end() )
cout << "Not Found!";
else
cout << "Found";
}
Fundamentally, you're inserting an element with the key "foo" and then searching for that element. Test the above code, and you'll find that it isn't found. If, however, you try this:
#include <map>
#include <iostream>
#include <string>
using namespace std;
int main()
{
typedef map<string,string> Strings;
Strings strings;
strings.insert(make_pair("foo","bar"));
string ss = "foo";
Strings::iterator it = strings.find(ss);
if( it == strings.end() )
cout << "Not Found~!";
else
cout << "Found";
}
...you get the behavior you really wanted.
What happens
Nothing. If you dynamically allocated memory, it'll leak - there's no automatic destructor for char*.
Use std::string or similar class instead.
I do agree that std::map<string, string> will have advantages over std::map<char*, char*>. Specially having the key as value rather than pointer would provide the expected search/find results.
But, sometimes we do need pointer in map definition specially in the value part when map’s value part is heavy object of a user defined class. By heavy object , I mean copy constructor of the class does a significant amount of work. In such scenarios, value part of the map should be a pointer. Using a raw pointer would leak the memory as mentioned above. Smart pointer would be a better choice ensuring no memory is leaked.
Sample example:
Consider the below class
class ABCD
{
public:
ABCD(const int ab) : a(ab)
{cout << "Constructing ABC object with value : " << a << endl;}
~ABCD()
{cout << "Destructing ABC object with value : "<< a << endl;}
void Print()
{ cout << "Value is : " << a << endl;}
private:
int a;
};
Consider the code where-in smart pointer of the above class is used:
{
std::map<_tstring, std::shared_ptr<ABCD>> myMap;
_tstring key(_T("Key1"));
myMap.insert(std::make_pair(key, std::make_shared<ABCD>(10)));
auto itr = myMap.find(key);
itr->second->Print();
myMap[key] = std::make_shared<ABCD>(20);
itr = myMap.find(key);
itr->second->Print();
} // myMap object is destroyed, which also calls the destructor of ABCD class
Output from above code is:
Constructing ABC object with value : 10
Value is : 10
Constructing ABC object with value : 20
Destructing ABC object with value : 10
Value is : 20
Destructing ABC object with value : 20