c++ - 实现指针元组的深度复制

标签 c++ tuples c++14 variadic-templates deep-copy

如果我错了请纠正我,但是在运行时

std::tuple<double*, bool*> t(new double(3.5), new bool(true));
print_tuple(t);
std::tuple<double*, bool*> n = t;
print_tuple(n);

我明白了

std::get<0>(t) = 0x1f13d0
std::get<1>(t) = 0x1f13b0
std::get<0>(n) = 0x1f13d0
std::get<1>(n) = 0x1f13b0

这意味着元组中的指针只是浅拷贝,对吧?所以我写了一个简单的实用程序,用于深度复制元组的所有指针元素:

template <std::size_t N, typename Tuple>
std::enable_if_t<std::is_pointer<std::tuple_element_t<N, Tuple>>::value> assign (Tuple& tuple, const Tuple& other) {
    std::get<N>(tuple) = new std::remove_pointer_t<std::tuple_element_t<N, Tuple>>(*std::get<N>(other));
}

template <std::size_t N, typename Tuple>
std::enable_if_t<!std::is_pointer<std::tuple_element_t<N, Tuple>>::value> assign (Tuple& tuple, const Tuple& other) {
    std::get<N>(tuple) = std::get<N>(other);
}

template <typename Tuple, std::size_t... Is>
Tuple deep_copy_impl (const Tuple& other, std::index_sequence<Is...>) {
    Tuple tuple = {};
    const int a[] = {(assign<Is>(tuple, other), 0)...};
    static_cast<void>(a);
    return tuple;
}

template <typename Tuple>
Tuple deep_copy (const Tuple& other) {
    return deep_copy_impl(other, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}

这对于上面的示例似乎工作正常,但是当我尝试使用由

定义的元组 tup
std::tuple<double*, bool*> t(new double(3.5), new bool(true));
std::tuple<int*, std::tuple<double*, bool*>*, char> tup(new int(5), &t, 'a');

我获得了元组指针的深拷贝,但元组指针中的指针再次被浅拷贝。我希望这些指针也能被深度复制。如何为任意数量的嵌套指针元组修复此问题?这是我的测试结果:

#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>

template <std::size_t N, typename Tuple>
std::enable_if_t<std::is_pointer<std::tuple_element_t<N, Tuple>>::value> assign (Tuple& tuple, const Tuple& other) {
    std::get<N>(tuple) = new std::remove_pointer_t<std::tuple_element_t<N, Tuple>>(*std::get<N>(other));
}

template <std::size_t N, typename Tuple>
std::enable_if_t<!std::is_pointer<std::tuple_element_t<N, Tuple>>::value> assign (Tuple& tuple, const Tuple& other) {
    std::get<N>(tuple) = std::get<N>(other);
}

template <typename Tuple, std::size_t... Is>
Tuple deep_copy_impl (const Tuple& other, std::index_sequence<Is...>) {
    Tuple tuple = {};
    const int a[] = {(assign<Is>(tuple, other), 0)...};
    static_cast<void>(a);
    return tuple;
}

template <typename Tuple>
Tuple deep_copy (const Tuple& other) {
    return deep_copy_impl(other, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}

// Testing
template <typename Tuple, std::size_t... Is>
std::ostream& print_tuple_impl (const Tuple& tuple, std::ostream& os, std::index_sequence<Is...>) {
    const int a[] = {(os << "std::get<" << Is << ">(tuple) = " << std::get<Is>(tuple) << '\n', 0)...};
    static_cast<void>(a);
    return os;
}

template <typename Tuple>
std::ostream& print_tuple (const Tuple& tuple, std::ostream& os = std::cout) {
    return print_tuple_impl (tuple, os, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}

int main() {
    std::tuple<double*, bool*> t(new double(3.5), new bool(true));
    print_tuple(t);
    std::tuple<double*, bool*> n = t;
    print_tuple(n);
    std::cout << "Above is shallow copying only.\n\n";

    std::tuple<int*, std::tuple<double*, bool*>*, char> tup(new int(5), &t, 'a');
    print_tuple(tup);
    std::tuple<int*, std::tuple<double*, bool*>*, char> q = deep_copy(tup); 
    print_tuple(q);
    std::cout << "\nAbove seems like a deep copy, but look at this:\n";

    print_tuple(*std::get<1>(tup));
    print_tuple(*std::get<1>(q));
}

输出:

std::get<0>(tuple) = 0x1f13d0
std::get<1>(tuple) = 0x1f13b0
std::get<0>(tuple) = 0x1f13d0
std::get<1>(tuple) = 0x1f13b0
Above is shallow copying only.

std::get<0>(tuple) = 0x1f13f0
std::get<1>(tuple) = 0x72fe10
std::get<2>(tuple) = a
std::get<0>(tuple) = 0x1f1410
std::get<1>(tuple) = 0x1f1430
std::get<2>(tuple) = a

Above seems like a deep copy, but look at this:
std::get<0>(tuple) = 0x1f13d0
std::get<1>(tuple) = 0x1f13b0
std::get<0>(tuple) = 0x1f13d0
std::get<1>(tuple) = 0x1f13b0

最佳答案

template<class T> T deep_copy(const T& t);
template<class T> T* deep_copy(T* tp);
template<class... Ts> std::tuple<Ts...> deep_copy(const std::tuple<Ts...>&);

template<class T>
T deep_copy(const T& t) { return t; }

template<class T>
T* deep_copy(T* tp) { return new T(deep_copy(*tp)); }

template<class... Ts, size_t... Is>
std::tuple<Ts...> deep_copy_impl(const std::tuple<Ts...>& t, std::index_sequence<Is...>) {
    return std::tuple<Ts...>{deep_copy(std::get<Is>(t))... };
}

template<class... Ts>
std::tuple<Ts...> deep_copy(const std::tuple<Ts...>& t) {
    return deep_copy_impl(tuple, std::index_sequence_for<Ts...>());
}

关于c++ - 实现指针元组的深度复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37016081/

相关文章:

python-3.x - 从元组组合对列表中进行选择,使得每个元组元素至少出现两次

c++ - 错误 : expected primary-expression before '<<' token

c++ - Eigen 中两个矩阵之间的成对差异

c++ - 更改数据忽略 const 限定符

c++ - 通过删除重复代码使我的 do while 循环更整洁

java - 将元组数组发送到准备好的语句

python - 通过字典的字典的元组获取值

C++ 使用函数参数类型进行模板参数推导

c++ - 如何正确实现 C++ 类析构函数

c++ - 范围末尾的左值可以被视为右值吗?