mardi 23 octobre 2018

Why can't I move-construct a unique_ptr with itself? [duplicate]

This question already has an answer here:

I was recently working with some code that uses a std::vector of std::unique_ptr<T> with a custom deleter of type std::function<void(T*)>. The code is attempting to remove values that meet a certain condition from the vector:

size_t j = 0;
for (size_t i = 0; i < vec.size(); i++) {
    if (!condition(vec[i].get()) {
            vec[j] = std::move(out[i]);
            j++;
    }
}
vec.resize(j);

In troubleshooting a bad_function_call thrown from the destructor of vec, I found that when i=j and a unique_ptr is move-constructed with itself, it loses its custom deleter. In other words, vec[j] will still point to the correct value, but its deleter will be a default-constructed std::function.

Why does this happen? What rule does this code break?

FWIW, I can only make it happen with clang, and only on certain platforms. Adding a guard for i=j fixes the problem.

MCVE:

#include <memory>
#include <vector>
#include <functional>

using int_ptr= std::unique_ptr<int, std::function<void(int*)>>;

int_ptr make_int_ptr(int val) {
    auto deleter = [](int* q) { delete q; };
    int* v = new int;
    *v = val;
    return int_ptr{v, deleter};
}

int main() {
    auto a = make_int_ptr(4);
    a = std::move(a);
}

Aucun commentaire:

Enregistrer un commentaire