Deleting a Modified Object from a Set in a No-Op

Deleting a modified object from a set in a no-op?

Yes, this is a bug or at least I'd call it a bug. Some would call this "an implementation detail accidentally leaking to the outside world" but that's just fancy pants city-boy talk for bug.

The problem has two main causes:

  1. You're modifying elements of the Set without Set knowing about it.
  2. The standard Ruby Set is implemented as a Hash.

The result is that you're modifying the internal Hash's keys without the Hash knowing about it and that confuses the poor Hash into not really knowing what keys it has anymore. The Hash class has a rehash method:

rehash → hsh

Rebuilds the hash based on the current hash values for each key. If values of key objects have changed since they were inserted, this method will reindex hsh.

a = [ "a", "b" ]
c = [ "c", "d" ]
h = { a => 100, c => 300 }
h[a] #=> 100
a[0] = "z"
h[a] #=> nil
h.rehash #=> {["z", "b"]=>100, ["c", "d"]=>300}
h[a] #=> 100

Notice the interesting behavior in the example included with the rehash documentation. Hashes keep track of things using the k.hash values for the key k. If you have an array as a key and you change the array, you can change the array's hash value as well; the result is that the Hash still has that array as a key but the Hash won't be able to find that array as a key because it will be looking in the bucket for the new hash value but the array will be in the bucket for the old hash value. But, if you rehash the Hash, it will all of a sudden be able to find all of its keys again and the senility goes away. Similar problems will occur with non-array keys: you just have to change the key in such a way that its hash value changes and the Hash containing that key will get confused and wander around lost until you rehash it.

The Set class uses a Hash internally to store its members and the members are used as the hash's keys. So, if you change a member, the Set will get confused. If Set had a rehash method then you could kludge around the problem by slapping the Set upside the head with rehash to knock some sense into it; alas, there is no such method in Set. However, you can monkey patch your own in:

class Set
def rehash
@hash.rehash
end
end

Then you can change the keys, call rehash on the Set, and your delete (and various other methods such as member?) will work properly.

Deleting the '__del__' method from an existing object in Python

The best thing yo do there, if you have access to the object's class code, is not to rely on __del__ at all. The fact of __del__ having a permanent side-effect could be a problem by itself, but in an environment using multiprocessing it is definitively a no-go!

Here is why: first __del__ is a method that lies on the instance's class, as most "magic" methods (and that is why you can't delete it from an instance). Second: __del__ is called when references to an object reach zero. However, if you don't have any reference to an object on the "master" process, that does not mean all the child processes are over with it. This is likely the source of your problem: reference counting for objects are independent in each process. And third: you don't have that much control on when __del__ is called, even in a single process application. It is not hard to have a dangling reference to an object in a dictionary, or cache somewhere - so tying important application behavior to __del__ is normally discouraged. And all of this is only for recent Python versions (~ > 3.5), as prior to that, __del__ would be even more unreliable, and Python would not ensure it was called at all.

So, as the other answers put it, you could try snooze __del__ directly on the class, but that would have to be done on the object's class in all the sub-processes as well.

Therefore the way I recommend you to do this is to have a method to be explicitly called that will perform the file-erasing and other side-effects when disposing of an object. You simply rename your __del__ method and call it just on the main process.

If you want to ensure this "destructor" to be called,Python does offer some automatic control with the context protocol: you will then use your objects within a with statement block - and destroy it with inside an __exit__ method. This method is called automatically at the end of the with block. Of course, you will have to devise a way for the with block just to be left when work in the subprocess on the instance have finished. That is why in this case, I think an ordinary, explicit, clean-up method that would be called on your main process when consuming the "result" of whatever you executed off-process would be easier.

TL;DR

  • Change your source object's class clean-up code from __del__ to an ordinary method, like cleanup
  • On submitting your instances to off-process executing, call the clean-up in your main-process, by using the concurrent.futures.as_completed call.

In case you can't change the source code for the object's class, inherit it,
override __del__ with a no-op method, and force the object's __class__ atribute to the inherited class before submitting it to other processes:

class SafeObject(BombObject):
def __del__(self):
pass

def execute(obj):
# this function is executed in other process
...

def execute_all(obj_list):
executor = concurrent.futures.ProcessPoolExecutor(max_workers=XX)
with executor:
futures = {}
for obj in obj_list:
obj.__class__ = SafeObject
futures[executor.submit(execute, obj)] = obj
for future in concurrent.futures.as_completed(futures):
value = future.result() # add try/except aroudn this as needed.
BombClass.__del__(obj) # Or just restore the "__class__" if the isntances will be needed elsewhere

del futures # Needed to clean-up the extra references to the objects created in the futures dict.

(please note that the "with" statement above is from the recommended usage for ProcessPoolExecutor, from the docs, not for the custom __exit__ method I suggested you using earlier in the answer. Having a with block equivalent that will allow you to take full advantage of the ProcessPoolExecutor will require some ingenuity into it)

Is it possible to delete a method from an object (not class) in python?

Looks like the way to dir() works by default is:

dir(obj) == sorted(obj.__dict__.keys() + dir(obj.__class__))

(well, removing duplicates anyway)

So an approach would be:

class Wizard(object):
def __init__(self):
self.mana = 0

def __dir__(self):
natdir = set(self.__dict__.keys() + dir(self.__class__))
if self.mana <= 0:
natdir.remove("domagic")
return list(natdir)

def addmana(self):
self.mana += 1

def domagic(self):
if self.mana <= 0:
raise NotEnoughMana()
print "Abracadabra!"
self.mana -= 1

With the behaviour in Py2.6 being:

>>> wiz = Wizard()

>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'mana']

>>> wiz.addmana()

>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'domagic', 'mana']

>>> wiz.domagic()
Abracadabra!

>>> [x for x in dir(wiz) if not x.startswith("_")]
['addmana', 'mana']

>>> wiz.domagic()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 13, in domagic
__main__.NotEnoughMana

Is it possible to delete an object in c++ without calling the destructor?

You can set the pointers to NULL, then the destructor will not delete them.

struct WithPointers
{
int* ptr1;
int* ptr2;

WithPointers(): ptr1(NULL), ptr2(NULL) {}

~WithPointers()
{
delete ptr1;
delete ptr2;
}
}

...
WithPointers* object1 = new WithPointers;
WithPointers* object2 = new WithPointers;
object1->ptr1 = new int(11);
object1->ptr2 = new int(12);
object2->ptr1 = new int(999);
object2->ptr2 = new int(22);
...
int* pointer_to_999 = object2->ptr1;
object2->ptr1 = NULL;
delete object1;
delete object2; // the number 999 is not deleted now!
// Work with the number 999
delete pointer_to_999; // please remember to delete it at the end!

How to remove element from unordered_set without elements being freed

You can extract the node that contains the element without destroying the element of the set.

I'm storing a collection of MyObject pointers

In this case, how about considering just making a copy of the pointer before erasing it from the set?

Deleting array elements in JavaScript - delete vs splice

delete will delete the object property, but will not reindex the array or update its length. This makes it appears as if it is undefined:

> myArray = ['a', 'b', 'c', 'd']
["a", "b", "c", "d"]
> delete myArray[0]
true
> myArray[0]
undefined

Note that it is not in fact set to the value undefined, rather the property is removed from the array, making it appear undefined. The Chrome dev tools make this distinction clear by printing empty when logging the array.

> myArray[0]
undefined
> myArray
[empty, "b", "c", "d"]

myArray.splice(start, deleteCount) actually removes the element, reindexes the array, and changes its length.

> myArray = ['a', 'b', 'c', 'd']
["a", "b", "c", "d"]
> myArray.splice(0, 2)
["a", "b"]
> myArray
["c", "d"]

Deleting node containing address of other node

In this statement of the operator delete

delete p;

all nodes that follow the node pointed to by the pointer p (due to the data member next) will be deleted.

So the function deleteAlternateNodes invokes undefined behavior because all nodes pointed to by the expression q->next that is assigned like

    q->next = p->next;

will be deleted due to this statement

    delete p;

So this statement

    p = q->next;

sets the pointer p to an invalid pointer.

Here is a demonstrative program

#include <iostream>

class Node
{
public:
int data;
Node * next;

Node(int data)
{
this -> data = data;
this -> next = NULL;
}

~Node()
{
std::cout << "The destructor is called for node with data equal to "
<< data << '\n';

if(next)
{
delete next;
}
}
};

void display( const Node *head )
{
for ( ; head; head = head->next )
{
std::cout << head->data << " -> ";
}

std::cout << "null\n";
}

int main()
{
Node *head = new Node( 1 );
Node *current = head;
current->next = new Node( 2 );
current = current->next;
current->next = new Node( 3 );

display( head );

delete head;

return 0;
}

The program output is

1 -> 2 -> 3 -> null
The destructor is called for node with data equal to 1
The destructor is called for node with data equal to 2
The destructor is called for node with data equal to 3

In fact the if statement in the destructor is redundant

        if(next) 
{
delete next;
}

You may just write

delete next;

without the if statement because for a null pointer the destructor will not be called. For example

~Node() 
{
std::cout << "The destructor is called for node with data equal to "
<< data << '\n';

delete next;
}

or

~Node() 
{
delete next;
}

No op delete for unique_ptr

As @101010 pointed out, that's very strange to have a std::unique_ptr with a nop deleter, since the only valuable thing std::unique_ptr has is actually the deleter. Also, you said that "C++ side expects a unique_ptr", but a std::unique_ptr with a different deleter would be a different type, and this may not work.

Nevertheless, here's the way to do it:

struct nop
{
template <typename T>
void operator() (T const &) const noexcept { }
};

template <typename T>
using nop_unique_ptr = std::unique_ptr<T, nop>;

Note that this nop type can be used as no-operation anywhere in place of a one-argument functor.

How to change the object of the class itself from inside itself?

Your #removeDuplicates method is attempting to mutate the list object it belongs to (known by this, within this class), and as such should actually make those modifications to the list itself (rather than a copy). Note as well, that by iterating your newly-made list wordDuplicate, the for loop will not actually execute (since there are no values inside the list). I would personally keep track using a Set (namely, HashSet with a roughly O(1) lookup, aka nearly constant-time), while taking advantage of the Iterator#remove method:

public void removeDuplicates() {
Set<T> seen = new HashSet<>();
Iterator<T> itr = this.iterator(); //similar to the mechanics behind for-each
while (itr.hasNext()) { //while another element can be found
T next = itr.next(); //get the next element
if (!seen.add(next)) { //#add returns "true" only if it was not in the Set previously
itr.remove(); //if it was previously in the set, remove it from the List
}
}
}

Note as well, that the semantics you are describing nicely fit the definition of a Set, which is a collection of items that do not contain duplicates. There are varients of Set (i.e. LinkedHashSet) which also allow linear traversal of the elements, based on insertion-order.

For a simpler, non-iterator solution, you could also do a "dirty swap" of the elements after your calculation, which would be similar to what you attempted to achieve via this = list:

public void removeDuplicates() {
Set<T> seen = new LinkedHashSet<>(); //to preserve iteration order
for (T obj : this) { //for each object in our current list
seen.add(obj); //will only add non-duplicates!
}
this.clear(); //wipe out our old list
this.addAll(seen); //add back our non-duplicated elements
}

This can be quicker to write, but would be less performant than the in-place removal (since the entire list must be wiped and added to again). Lastly, if this is a homework problem, try to avoid copy-pasting code directly, and instead write it out yourself at the very least. Merely working towards a solution can help to solidify the information down the line.



Related Topics



Leave a reply



Submit