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:
- You're modifying elements of the Set without Set knowing about it.
- 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, likecleanup
- 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
Putting the Results of Pp (Or Anything Outputted to Console) into a String
Finding If a Sentence Contains a Specific Phrase in Ruby
Ruby-Debug19 on Ruby-1.9.3-Preview1
How to Use Savon Nested Attributes! Hash
Uninitialized Constant "Controller Name"
Ruby | Find a Way to Find an Exception on the Same Word to Capitalize
Ruby, !! Operator (A/K/A the Double-Bang)
Lisp and Erlang Atoms, Ruby and Scheme Symbols. How Useful Are They
HTML Code Inside Buttons with Simple_Form
Replace "&" to "\&" in Ruby Seems Impossible
How to Improve Jruby Load Time
Why Does Ruby's String#To_I Sometimes Return 0 When the String Contains a Number