for(ItemTemplateListIterator iter = item_template_list.begin(); iter != item_template_list.end(); ++iter) {
int id = iter->first;
string description = iter->second->description;
some_file_stream << id << endl;
some_file_stream << description << endl;
}
Where item_template_list is a map of <int, MyClass*>, ItemTemplateListIterator is a typedef for a const_iterator of map<int, MyClass*> and MyClass has a public string property called description.
What very likely happened is that the object pointers that you stored in the map are not valid anymore (because the memory was deallocated elsewhere). Attempting to access a deallocated memory area causes a segfault. Not valid is meaning either NULL or having a so-called "dangling pointer".
Maybe also you are modifying the map or objects in the map in another thread while iterating through it.
There is too little code here for me to help you more.
I'll take a shot.
One of the MyClass* (pointers) has a "junk" (incorrect) value when you try to access it and boo-m. Segfault city.
As commented, you can store the full object in the map and not bother with pointers.
one of (iter->second) == null
The reason this is segfault is probably because the MyClass* is null or has been freed and has garbage value.
You can easily find out if it's null:
MyClass * obj = iter->second;
if (obj == null) {
cerr << "Unexpected null pointer" << endl;
} else {
string description = obj->description;
some_file_stream << id << endl;
some_file_stream << description << endl;
}
However, you still need to go through the rest of your code that populates the list and find out why it's not what you expected it to be.
Overall I'd say unless you're aiming to eliminate unnecessary copying of objects you'll be safer to store actual objects in the list and just make sure your copy constructor can handle them.
Related
I have a Player object which holds an ID string. I'm trying to check if a player already exists by iterating through a list of Players. If the player already exists, I want to return the existing player, else I will make a new instance of the Player object.
Player *playerExists(const std::string &playerId, const std::vector<Player>* players)
{
for (Player existingPlayer : *players)
{
if (existingPlayer.playerId == playerId)
{
std::cout << "Player " << existingPlayer.name << " exists" << std::endl;
return &existingPlayer;
}
}
return new Player();
}
The problem seems to be in the return statement. I don't know how to return the specific object to a pointer. This seems to be the only way I found not to get an error (talking about the & sing in the return statement).
Player* player = playerExists("SomeID", listOfPlayers);
listOfPlayers->push_back(*player);
delete player;
I'm quite new to using raw pointers so I probably just don't understand what the problem here is. I'd really appreciate if someone could explain what I'm doing wrong.
There are several issues with this code.
Each iteration of the loop is making a local copy of a Player in the vector, and thus will return a pointer to that copy if a match is found. But when the current iteration is finished, that copy is destroyed, so you will end up returning a dangling pointer. To fix that, your loop need to take a reference to each Player in the vector:
for (Player &existingPlayer : *players)
The next issue is if no match is found, you return a newed Player. The problem with that is the caller is then unconditionally deleteing the returned Player* regardless of whether it was newed or not. The vector owns the Player objects it is holding, so deleteing one of those objects is undefined behavior.
A better design choice is to have playerExists() return nullptr if no match is found. The caller can then do different things depending on whether a Player or a nullptr is returned, eg:
Player* playerExists(const std::string &playerId, const std::vector<Player>* players)
{
for (Player &existingPlayer : *players)
{
if (existingPlayer.playerId == playerId)
{
std::cout << "Player " << existingPlayer.name << " exists" << std::endl;
return &existingPlayer;
}
}
return nullptr;
}
Player* player = playerExists("SomeID", listOfPlayers);
if (player) {
// ID found, use player as needed...
listOfPlayers->push_back(*player); // why re-add a player that is already in the list???
} else {
// ID not found, do something else...
listOfPlayers->push_back(Player{}); // why add a blank player???
}
Different ways of tackling this. Biggest problem might be in this line:
for (Player existingPlayer : *players)
It's making a copy (I think) of a player already in the collection.
When you do a return &existingPlayer; ... well it's returning an object on the stack. Bad things will happen.
You are better off iterating the collection and returning an iterator, IMHO... Maybe...
std::vector<Player>::const_iterator playerExists(const std::string &playerId, const std::vector<Player>& players)
{
std::vector<Player>::const_iterator it = players.begin();
for (; it != players.end(); ++it)
{
if (it->playerId == playerId)
{
std::cout << "Player " << it->name << " exists" << std::endl;
break;
}
}
return it;
}
You can always test after the return for
With the returned iterator, you'll have to do something with it...
auto it = playerExists(playerId, players);
if (it == players.end())
{
// not found
} else {
// found
}
Your problem is there :
for (Player existingPlayer : *players)
In each iteration of the for loop, existingPlayer is a copy of the player that is stored in a local variable in the scope of the for loop. You are returning a pointer to a local variable which get destroyed after each loop iteration.
To avoid the copy, use a reference :
for (Player &existingPlayer : *players)
Here, existingPlayer is a reference to the real player. This is what you did with the const std::string in the function prototype.
I have also some suggestions to possibly improve your code :
Avoid raw C pointers, C++ give you tools to get the same functionnality in a (much) less error prone way and hence, more secure. If you don't need NULL as I see in your code, a reference is probably better. Else you should consider smart pointers (std::unique_ptr, std::shared_ptr. I would pass players by reference instead of pointers in your case.
std::vector may not be the best container. Choosing the right container can be difficult. Currently you are iterating over the whole array to find the player by his id. You should use a std::unordered_map<std::string,Player> that use a hash table and probably speed up lookup time. I would also use a typedef of std::a_container_class<Player> to avoid massive code rewrite if you change the container kind or write one from scratch later.
Does copying a Player make sense ? If not, explicitly delete copy constructor and copy assignment operator, the compiler will then throw an error if you want to copy the Player. Note that this is a design choice that I often do, multiple instance of the same player is normal depending on your objects design.
I'm doubtful about return new Player();. Why do you return a new player if no player exist ? With my personal interpretation (might be totally wrong), I would return an iterator. No pointer involved, you can "dereference" the iterator to get a reference to the found player and the non existence of player is signaled by return an iterator equal to players.end(). But beware a big drawback, be sure to test before modifying the container and invalidating iterators.
With my own design choices, I made a slightly untested and shorter version of your function :
#include <unordered_map>
typedef std::unordered_map<std::string,Player> PlayerCollection;
/* ... */
PlayerCollection::const_iterator playerExists(const std::string &playerId, const PlayerCollection &players)
{
return players.find(playerId);
}
Keep in mind that my suggestions are opinionated and are not the absolute truth. Read the other answers which have different ideas.
I'm facing some jsoncpp issues with memory corruption.
When I assign some values in local Json::Value variable, sometimes It gets a wrong data and make a crash.
so I'm trying to make Json::value variable with dynamic allocation and check memory corruption more carefully.
anyway, my question is, Can I use jsoncpp with dynamic allocation ? and Do you think it is safe than before?
I'm so sorry for my lacking in english.
Thank you !
JsonCpp may get unhandy when you want to manage references to values in the tree on your own, or when you want to refer to internals of the values.
See the following code that describes three ways of how it can be used savely as well as two samples that show some common pitfalls. Hope it helps a bit.
Note that when dealing with "dynamic allocation", often smart pointers are very handy and can reduce the risk of memory leaks or memory corruption due to bugs in allocating/deleting objects at the right point. Confer, for example, shared_ptr.
Json::Value createJsonValue() {
Json::Value json("a string value");
return json; // OK - enforces a copy
}
Json::Value *createJsonValueReference() {
Json::Value *json_dynamic = new Json::Value("a string value");
return json_dynamic; // OK - does not enforce a copy but keeps json value in heap
}
std::shared_ptr<Json::Value> createJsonValueSmartPointer() {
std::shared_ptr<Json::Value> result(new Json::Value("a string value"));
return result; // OK - creates a json::value on the heap and wraps it by a shared_ptr object
}
Json::Value &referenceToLocalJson() {
Json::Value json("a string value");
return json; // Not OK: Reference to stack memory associated with local variable `json` returned
}
const char* getJsonValueContent() {
Json::Value json("a string value");
return json.asCString(); // critical: reference to internals of object that will be deleted.
}
int main()
{
Json::Value copied = createJsonValue(); // will be a copy; lifetime is until end of main
Json::Value *ptr = createJsonValueReference(); // will be a reference to an object on the heap; lifetime until you call `delete ref`
std::shared_ptr<Json::Value> smartptr = createJsonValueSmartPointer(); // share_ptr object, managing a reference to an object on the heap; lifetime of shared_ptr until end of main; lifetime of referenced object until the last shared_ptr pointing to it is destroyed
Json::Value &critical = referenceToLocalJson(); // Critical; will refer to an object that has already been deleted at the end of "referenceToLocalJson"
const char* content = getJsonValueContent(); // critical: reference to internals of object that will be deleted.
cout << "copied:" << copied << std::endl;
cout << "reference:" << *ptr << std::endl;
cout << "smartptr:" << *smartptr << std::endl;
// cout << "critical:" << critical << std::endl; // undefined outcome
// cout << "content:" << content << std::endl; // undefined outcome
delete ptr; // OK - will free object referred to by ptr
// smartptr will be deleted together with the json value it refers to at the end of this function; no "explicit" delete
return 0;
}
I have a list that stores objects.
list<MyObject> l;
I also have a method that returns a pointer to one of those objects, if it exists, or nullptr otherwise.
MyObject* get(int x) {
for (std::list<MyObject>::iterator it = l.begin(); it != l.end(); ++it) {
if (it->X == x) {
return &(*it);
}
}
return nullptr;
}
If I get() a pointer to an element, and while I am using it, it gets erased from another thread, the pointer becomes invalid, and weird things happen :)
What I wanted to know is if there is a way of returning some special kind of pointer in get(), so that if I call erase on an element and that element is still being referenced, its memory won't be released until the pointer to it goes out of scope.
I considered using a reference, but I need the possibility of returning nullptr on get, so I can check from the caller if the return was indeed a valid object.
Can someone suggest a better way of doing this, to avoid these memory issues?
As recommended you should use some smart_pointer to manage the shared ownership.
Some recomendations:
Use always as default, std::vector
If could use C++11 use the standard shared_ptr for shared ownership, if not, use boost version.
Use the algorithm header as much as you can (in this case find_if is the right one).
You should also try to use the algorithm for the search of the specific element. Here is some sample code:
#include <algorithm>
#include <iostream>
#include <vector>
#include <memory>
struct MyObject {
int X;
MyObject(int x_value) : X(x_value) {}
};
using element_t = std::shared_ptr<MyObject>;
std::vector<element_t> l{
std::make_shared<MyObject>(3), std::make_shared<MyObject>(4),
std::make_shared<MyObject>(5), std::make_shared<MyObject>(6),
std::make_shared<MyObject>(7), std::make_shared<MyObject>(8)};
element_t get(int x) {
auto it = std::find_if(std::begin(l), std::end(l),
[x](const element_t& elem) { return elem->X == x; });
element_t found;
if (it != std::end(l)) {
found = *it;
}
return found;
}
int main() {
auto f1 = get(6);
if (f1) {
std::cout << "encontrado " << f1->X << std::endl;
} else {
std::cout << "6 no se encontro" << std::endl;
}
auto f2 = get(10);
if (f2) {
std::cout << "encontrado " << f2->X << std::endl;
} else {
std::cout << "10 no se encontro" << std::endl;
}
return 0;
}
Before using smart pointers, you might want to make sure you can spell out the reason why you can't (or don't want to) design a system where your objects have only one owner at a given time.
Smart pointers will avoid invalid data access, but they have all sorts of more or less hidden problems
they cost additional memory, force you to use them and their move semantics everywhere, and might easily become tricky, e.g. if you keep circular references or want an object to return a smart pointer to itself,
std:: containers become basically as useless as when you fill them with any kind of pointers (a vector of pointers is not a vector of objects),
you don't control where the deallocation takes place, so you might have your objects deleted by any task referencing them, possibly a time-critical one,
having no clear idea of who owns what is more often than not a recipe for disaster.
For instance, having one thread decide to delete objects while another grabs some from the same storage without any synchronization is very dangerous indeed. It is a bit as if one thread considered the object invalid while the other would consider it valid.
Does not strike me as the most robust design, but surely you have your reasons.
I think you could start by using unique_ptrs and see if that suits your needs, instead of jumping to shared_ptrs right away.
I need to create object pointers in a loop, but I am struggling with creating unique pointers. Here's my code:
class DatClass{
public:
int m;
DatClass(int i):m(i){}
};
class OtherClass{
public:
DatClass* dc;
};
void Test(std::vector<OtherClass> v){
std::vector<OtherClass>::iterator it;
int i = 1;
for(it = v.begin(); it != v.end(); it++){
DatClass dc = DatClass(i);
std::cout << &dc << std::endl;
it->dc = &dc;
i++;
}
}
int main(){
std::vector<OtherClass> v;
v.push_back(OtherClass());
v.push_back(OtherClass());
v.push_back(OtherClass());
Test(v);
}
This does not give me unique pointers. The output reads:
0xbf94d72c
0xbf94d72c
0xbf94d72c
Do I need to use new in order to get unique pointers? If so, where would I put the corresponding delete?
Thanks!
Yes, you should use new to get unique addresses.
The delete should be when the loop is done - otherwise (delete is inside the same loop) - the OS could give you the same address again.
(Or to be exact - when you are done with the object allocated in this address)
What's going on in your code is that you use an automatically allocated memory. This memory is usually allocated on the stack - and in each iteration - the same memory is reused for the variable - thus it gives you the same address.
DatClass dc = DatClass(i); creates an instance of the class on the stack. Its address remains the same in the loop, that's why the output is the same.
You may want to do following:
void Test(const std::vector<OtherClass>& v){
std::vector<OtherClass>::iterator it;
for(it = v.begin(); it != v.end(); it++){
const DatClass& dc = *it;
std::cout << &dc << std::endl;
}
}
Each iteration of the loop inside Test creates a new DatClass instance on the stack and prints its address. Before the next iteration, this object's lifetime ends and this enables the compiler to reuse the same memory on the next iteration.
This is why you always see the same address (of course it's only possible because the standard specifically allows the compiler to do that).
If you want to see different addresses for the objects then you should either allocate all of them in function scope outside the loop (in which case they will reside on the stack but at different addresses) or else allocate them on the heap.
Of course it should be obvious that it doesn't make any difference what the vector itself contains, since this affects only the number of iterations the loop does. If you change the code to print the addresses of the objects actually inside the vector you will also see different addresses.
Short you are trying to do this dynamically. This means nu are not on stack you are on heap. So more memory will be allocated only if you need or use it not at program start up.
So int a = 5; <<< stack and new int* b = 55(when finished using it you MUST free the memory with delete b; or bad segmentation fault errors you will get later.);
`cout<< &b;` prints the value stored at the pointer ` 55`
`cout<< *b` prints the pointers value in memory `#1234` i think this is called offset
i recomand you for this kind of basic questions:
http://www.cplusplus.com/doc/tutorial/
I think you may be trying to assign a new DatClass to OtherClass, but instead you're assigning an auto (on the stack) DatClass, that is destroyed at each loop iteration, because it's an automatic object (and the compiler is reusing its address on the stack, that's why you always see the same address)
I'd rather replace this:
for(it = v.begin(); it != v.end(); it++){
DatClass dc = DatClass(i); // auto object destroyed and address reused
std::cout << &dc << std::endl;
it->dc = &dc;
with this:
for(it = v.begin(); it != v.end(); it++){
DatClass *dc = new DatClass(i); // new object on heap
std::cout << dc << std::endl;
it->dc = dc;
so now you are creating new DatClass objects to assign to OtherClass objects.
(besides, you should also somewhere delete those new DatClass objects, to avoid resource leaks)
You print the address of dc. dc is on the stack at the same location every time. That's why you get the identical address every time.
You could change your loop to:
for (auto it = v.begin(); it != v.end(); ++it){
OtherClass *oc = &(*it);
std::cout << oc << std::endl;
}
which gives you the addresses of all objects in v
So here is the code I am dealing with:
class A
{
public:
A(){}
virtual ~A(){}
void Log(){printf("Log A\n");}
};
int main(int argc, char**argv)
{
A* a = new A();
a->Log(); // "Log A"
map<int,A*> m;
m[1] = a;
m[2] = a;
m[3] = a;
m[1]->Log(); // "Log A"
delete a;
a = NULL;
m[1]->Log(); // "Log A"
return 0;
}
Output:
Log A
Log A
Log A
My questions:
Is it only by chance that calling m[1]->Log() does not throw exception after delete a?
What's the best approach to erase all the entries in the map pointing to the deleted instance of A? I mean I want all m.find(1), m.find(2) and m.find(3) to return m.end() after deleting a. Any advice would be appreciated.
Yes and no. Technically it's undefined behavior, but usually (don't rely on this) calling non-virtual methods that don't access members appears to work on most compilers because most compilers implement this call without dereferencing this (which is the invalid part). So, in the standard's opinion, it's by chance. For most compilers, it's intended (or at least a side-effect of how function calls are handled).
Use smart pointers instead. To remove the elements, you can iterate through the map and compare each value to yours. When you reach one, use erase. Iterators are invalidated after erase.
Anything that happens when you dereference a deleted object is undefined behaviour, so even getting an exception could be considered to be "by chance"
The best approach is to couple the deletion of the object that is pointed to with the lifetime of something you have a handle on. So in your case, you could decide that it is best if the object is deleted if the pointer is removed from the map. To achieve this, you could use a map of int to std::unique_ptr<A> instead of one of raw pointers.
Edit: After looking at the requirements in more detail:
Now, since you want to remove elements whose mapped type points to a deleted object, and there is no way to determine whether the memory a pointer points to has been deleted, I see no simple way of removing these entries from the map other than doing it all in one function call. And since std::map et al do not like std::remove_if, one can use a loop:
template <typename T1, typename T2>
void removeEntriesAndDelete(std::map<T1, T2*>& m, T2*& item) {
for (auto i = m.begin(); i != m.end(); ) {
if ( item == i->second) {
m.erase(i++);
} else {
++i;
}
}
delete item;
item=0;
}
int main() {
A* a = new A;
std::map<int,A*> m;
m[1] = a;
m[2] = a;
m[3] = a;
std::cout << std::boolalpha;
std::cout << a << ", " << bool(m[1]) << ", " << bool(m[2]) << ", " << bool(m[3]) <<"\n";
removeEntriesandDelete(m, a);
std::cout << a << ", " << bool(m[1]) << ", " << bool(m[2]) << ", " << bool(m[3]) <<"\n";
}
Generally, objects which enrolled somewhere must notify the object where
they are enrolled. In simple cases like your example code, it's
relatively simple to go through the map, erasing each element which
points to your object, but I assume that your actual use case is less
trivial. The usual solution (in fact, the only one which really works
in practice) involves the observer pattern; when an object saves a
pointer to your object, either directly or in a map or a list or
whatever, it also enrols with your object, requesting notification when
your object is destructed. Your object keeps a list of these observers,
and will notify them in its destructor. Applied to a simple case like
yours, it looks like a lot of unnecessary code, but in the context of
actual applications where this pattern occurs, it's not that much.
It works by luck as you mention.
Either use something like smart pointers as previously mentioned, or encapsulate the map and value handling in a class, where you could have a method that removes the object from the map and deletes the object.