实现指针元组的深度复制
Implementing deep copying of tuple of pointers
如果我错了请纠正我,但是当 运行
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...>());
}
将 T.C. 的想法扩展到 STL 容器:
#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>
#include <vector>
#include <set>
template <typename T>
using void_t = void;
template <typename T, typename = void>
struct has_emplace_back : std::false_type {};
template <typename T>
struct has_emplace_back<T, void_t<decltype(std::declval<T>().emplace_back(std::declval<typename T::value_type>()))>> : std::true_type {};
template <typename T, typename = void>
struct has_emplace : std::false_type {};
template <typename T>
struct has_emplace<T, void_t<decltype(std::declval<T>().emplace(std::declval<typename T::value_type>()))>> : std::true_type {};
// etc... for other container types.
template <typename T>
struct is_stl_container : std::integral_constant<bool, has_emplace_back<T>::value || has_emplace<T>::value> {};
template <typename Container> std::enable_if_t<has_emplace_back<Container>::value, Container> deep_copy (const Container&);
template <typename Container> std::enable_if_t<has_emplace<Container>::value, Container> deep_copy (const Container&);
template <typename... Ts> std::tuple<Ts...> deep_copy (const std::tuple<Ts...>&); // This forward declarations, though not needed to compile, is needed for the nested deep copying to work correctly.
template <typename T>
std::enable_if_t<!is_stl_container<T>::value, T> deep_copy (const T& t) {
return t;
}
template <typename T>
T* deep_copy (T* t) {
return new T(deep_copy(*t)); // Note that since T's copy constructor is called here, then if T is a custom class that has its own custom copy constructor that carries out deep copying, then t's pointer data members are also deep copied.
}
template <typename... Ts, std::size_t... Is>
std::tuple<Ts...> deep_copy_impl (const std::tuple<Ts...>& tuple, std::index_sequence<Is...>) {
return std::tuple<Ts...>{ deep_copy(std::get<Is>(tuple))... };
}
template <typename... Ts>
std::tuple<Ts...> deep_copy (const std::tuple<Ts...>& tuple) {
return deep_copy_impl(tuple, std::index_sequence_for<Ts...>{});
}
template <typename Container>
std::enable_if_t<has_emplace_back<Container>::value, Container> deep_copy (const Container& c) {
Container container;
for (const typename Container::value_type& t : c)
container.emplace_back(deep_copy(t));
return container;
}
template <typename Container>
std::enable_if_t<has_emplace<Container>::value, Container> deep_copy (const Container& c) {
Container container;
for (const typename Container::value_type& t : c)
container.emplace(deep_copy(t));
return container;
}
// 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 and below show that we have full deep copying:\n";
print_tuple(*std::get<1>(tup));
print_tuple(*std::get<1>(q));
std::cout << "\nDeep copy of a vector of pointers:\n";
std::vector<int*> v = {new int(5), new int(2), new int(8)};
for (int* x : v) std::cout << x << ' '; std::cout << '\n';
std::vector<int*> u = deep_copy(v);
for (int* x : u) std::cout << x << ' '; std::cout << '\n';
std::cout << "\nDeep copy of a set of pointers:\n";
std::set<int*> s = {new int(5), new int(2), new int(8)};
for (int* x : s) std::cout << x << ' '; std::cout << '\n';
std::set<int*> ss = deep_copy(s);
for (int* x : ss) std::cout << x << ' '; std::cout << '\n';
}
输出:
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
Above is shallow copying only.
std::get<0>(tuple) = 0x8513f0
std::get<1>(tuple) = 0x72fd70
std::get<2>(tuple) = a
std::get<0>(tuple) = 0x851410
std::get<1>(tuple) = 0x851470
std::get<2>(tuple) = a
Above and below show that we have full deep copying:
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
std::get<0>(tuple) = 0x851430
std::get<1>(tuple) = 0x851450
Deep copy of a vector of pointers:
0x851490 0x8514b0 0x8514d0
0x851510 0x851550 0x851530
Deep copy of a set of pointers:
0x851570 0x8515c0 0x8515e0
0x851690 0x851800 0x851870
如果我错了请纠正我,但是当 运行
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...>());
}
将 T.C. 的想法扩展到 STL 容器:
#include <iostream>
#include <type_traits>
#include <utility>
#include <tuple>
#include <vector>
#include <set>
template <typename T>
using void_t = void;
template <typename T, typename = void>
struct has_emplace_back : std::false_type {};
template <typename T>
struct has_emplace_back<T, void_t<decltype(std::declval<T>().emplace_back(std::declval<typename T::value_type>()))>> : std::true_type {};
template <typename T, typename = void>
struct has_emplace : std::false_type {};
template <typename T>
struct has_emplace<T, void_t<decltype(std::declval<T>().emplace(std::declval<typename T::value_type>()))>> : std::true_type {};
// etc... for other container types.
template <typename T>
struct is_stl_container : std::integral_constant<bool, has_emplace_back<T>::value || has_emplace<T>::value> {};
template <typename Container> std::enable_if_t<has_emplace_back<Container>::value, Container> deep_copy (const Container&);
template <typename Container> std::enable_if_t<has_emplace<Container>::value, Container> deep_copy (const Container&);
template <typename... Ts> std::tuple<Ts...> deep_copy (const std::tuple<Ts...>&); // This forward declarations, though not needed to compile, is needed for the nested deep copying to work correctly.
template <typename T>
std::enable_if_t<!is_stl_container<T>::value, T> deep_copy (const T& t) {
return t;
}
template <typename T>
T* deep_copy (T* t) {
return new T(deep_copy(*t)); // Note that since T's copy constructor is called here, then if T is a custom class that has its own custom copy constructor that carries out deep copying, then t's pointer data members are also deep copied.
}
template <typename... Ts, std::size_t... Is>
std::tuple<Ts...> deep_copy_impl (const std::tuple<Ts...>& tuple, std::index_sequence<Is...>) {
return std::tuple<Ts...>{ deep_copy(std::get<Is>(tuple))... };
}
template <typename... Ts>
std::tuple<Ts...> deep_copy (const std::tuple<Ts...>& tuple) {
return deep_copy_impl(tuple, std::index_sequence_for<Ts...>{});
}
template <typename Container>
std::enable_if_t<has_emplace_back<Container>::value, Container> deep_copy (const Container& c) {
Container container;
for (const typename Container::value_type& t : c)
container.emplace_back(deep_copy(t));
return container;
}
template <typename Container>
std::enable_if_t<has_emplace<Container>::value, Container> deep_copy (const Container& c) {
Container container;
for (const typename Container::value_type& t : c)
container.emplace(deep_copy(t));
return container;
}
// 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 and below show that we have full deep copying:\n";
print_tuple(*std::get<1>(tup));
print_tuple(*std::get<1>(q));
std::cout << "\nDeep copy of a vector of pointers:\n";
std::vector<int*> v = {new int(5), new int(2), new int(8)};
for (int* x : v) std::cout << x << ' '; std::cout << '\n';
std::vector<int*> u = deep_copy(v);
for (int* x : u) std::cout << x << ' '; std::cout << '\n';
std::cout << "\nDeep copy of a set of pointers:\n";
std::set<int*> s = {new int(5), new int(2), new int(8)};
for (int* x : s) std::cout << x << ' '; std::cout << '\n';
std::set<int*> ss = deep_copy(s);
for (int* x : ss) std::cout << x << ' '; std::cout << '\n';
}
输出:
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
Above is shallow copying only.
std::get<0>(tuple) = 0x8513f0
std::get<1>(tuple) = 0x72fd70
std::get<2>(tuple) = a
std::get<0>(tuple) = 0x851410
std::get<1>(tuple) = 0x851470
std::get<2>(tuple) = a
Above and below show that we have full deep copying:
std::get<0>(tuple) = 0x8513d0
std::get<1>(tuple) = 0x8513b0
std::get<0>(tuple) = 0x851430
std::get<1>(tuple) = 0x851450
Deep copy of a vector of pointers:
0x851490 0x8514b0 0x8514d0
0x851510 0x851550 0x851530
Deep copy of a set of pointers:
0x851570 0x8515c0 0x8515e0
0x851690 0x851800 0x851870