C++ 比较共享指针的堆栈
C++ Compare stacks of shared pointers
假设我有一个堆栈,其中包含 int
的共享指针,如下所示:
#include <stack>
#include <memory>
using namespace std;
int main()
{
stack<shared_ptr<int>> s1;
stack<shared_ptr<int>> s2;
shared_ptr<int> v1 = make_shared<int>(1);
shared_ptr<int> v2 = make_shared<int>(1);
s1.push(v1);
s2.push(v2);
bool areEqual = s1 == s2; // This is false
}
如何让堆栈比较 shared_ptr
指向的实际值而不是指针本身?
std::stack
有一个受保护的成员c
,它是底层容器类型的一个实例。您可以制作一个访问该变量的堆栈包装器,然后按如下方式比较底层容器的内容:
#include <iostream>
#include <stack>
#include <memory>
#include <algorithm>
using namespace std;
template<class stack_type>
struct stack_wrapper : stack_type
{
auto begin() const
{
return stack_type::c.begin();
}
auto end() const
{
return stack_type::c.end();
}
};
template<class stack_type>
const stack_wrapper<stack_type> &wrap(const stack_type &stack)
{
return static_cast<const stack_wrapper<stack_type> &>(stack);
}
int main() {
stack<shared_ptr<int>> s1;
stack<shared_ptr<int>> s2;
shared_ptr<int> v1 = make_shared<int>(1);
shared_ptr<int> v2 = make_shared<int>(1);
s1.push(v1);
s2.push(v2);
const auto &s1wrapper = wrap(s1);
const auto &s2wrapper = wrap(s2);
const auto is_equal = std::equal(s1wrapper.begin(),
s1wrapper.end(),
s2wrapper.begin(),
s2wrapper.end(),
[](auto &first, auto &second) {
return first && second && *first == *second;
});
std::cout << is_equal << std::endl;
}
我喜欢。它准确地展示了 "encapsulating" 受保护的可访问性的真实情况。但是,将基础 class 子对象引用转换为派生的 class 子对象引用,然后将其视为一个子对象引用会很快导致未定义的行为。
然而,提取 c
成员的想法是合理的。我们可以通过一个简单的实用程序在没有 UB 风险的情况下做到这一点:
template<class S>
constexpr decltype(auto) stack_c(S&& s) {
using base = std::decay_t<S>;
struct extractor : base {
using base::c;
};
constexpr auto c_ptr = &extractor::c;
return std::forward<S>(s).*c_ptr;
}
由于表达式 &extractor::c
works,我们实际上获得了一个指向 base
成员的指针(std::stack
特化),名为 c
. extractor
的目的是通过 using 声明使名称可公开访问。
然后我们转发回对它的引用,值类别保留和所有。 @RealFresh 建议使用 std::equal
:
bool areEqual = std::equal(
stack_c(s1).begin(), stack_c(s1).end(),
stack_c(s2).begin(), stack_c(s2).end(),
[](auto const& p1, auto const& p2) {
return first && second && (p1 == p2 || *p1 == *p2);
}
);
假设我有一个堆栈,其中包含 int
的共享指针,如下所示:
#include <stack>
#include <memory>
using namespace std;
int main()
{
stack<shared_ptr<int>> s1;
stack<shared_ptr<int>> s2;
shared_ptr<int> v1 = make_shared<int>(1);
shared_ptr<int> v2 = make_shared<int>(1);
s1.push(v1);
s2.push(v2);
bool areEqual = s1 == s2; // This is false
}
如何让堆栈比较 shared_ptr
指向的实际值而不是指针本身?
std::stack
有一个受保护的成员c
,它是底层容器类型的一个实例。您可以制作一个访问该变量的堆栈包装器,然后按如下方式比较底层容器的内容:
#include <iostream>
#include <stack>
#include <memory>
#include <algorithm>
using namespace std;
template<class stack_type>
struct stack_wrapper : stack_type
{
auto begin() const
{
return stack_type::c.begin();
}
auto end() const
{
return stack_type::c.end();
}
};
template<class stack_type>
const stack_wrapper<stack_type> &wrap(const stack_type &stack)
{
return static_cast<const stack_wrapper<stack_type> &>(stack);
}
int main() {
stack<shared_ptr<int>> s1;
stack<shared_ptr<int>> s2;
shared_ptr<int> v1 = make_shared<int>(1);
shared_ptr<int> v2 = make_shared<int>(1);
s1.push(v1);
s2.push(v2);
const auto &s1wrapper = wrap(s1);
const auto &s2wrapper = wrap(s2);
const auto is_equal = std::equal(s1wrapper.begin(),
s1wrapper.end(),
s2wrapper.begin(),
s2wrapper.end(),
[](auto &first, auto &second) {
return first && second && *first == *second;
});
std::cout << is_equal << std::endl;
}
我喜欢
然而,提取 c
成员的想法是合理的。我们可以通过一个简单的实用程序在没有 UB 风险的情况下做到这一点:
template<class S>
constexpr decltype(auto) stack_c(S&& s) {
using base = std::decay_t<S>;
struct extractor : base {
using base::c;
};
constexpr auto c_ptr = &extractor::c;
return std::forward<S>(s).*c_ptr;
}
由于表达式 &extractor::c
works,我们实际上获得了一个指向 base
成员的指针(std::stack
特化),名为 c
. extractor
的目的是通过 using 声明使名称可公开访问。
然后我们转发回对它的引用,值类别保留和所有。 @RealFresh 建议使用 std::equal
:
bool areEqual = std::equal(
stack_c(s1).begin(), stack_c(s1).end(),
stack_c(s2).begin(), stack_c(s2).end(),
[](auto const& p1, auto const& p2) {
return first && second && (p1 == p2 || *p1 == *p2);
}
);