C++ 在编写智能指针和指针的通用代码时,如何获取简单指针?

C++ 在编写智能指针和指针的通用代码时,如何获取简单指针?,c++,c++11,C++,C++11,当我想要实现一个功能时: template <typename TIterator> void doSomething(TIterator begin, TIterator end); 也就是说,每当我需要一个普通指针时,使用双解引用*,后跟&运算符 它确实起到了作用,但我很好奇,是否有更具可读性、更常用的方法来实现这一点,以及在我用丑陋的东西(如&(**begin)填充代码后,是否有一些东西会再次困扰我: #include <memory> template <

当我想要实现一个功能时:

template <typename TIterator>
void doSomething(TIterator begin, TIterator end);
也就是说,每当我需要一个普通指针时,使用双解引用
*
,后跟
&
运算符


它确实起到了作用,但我很好奇,是否有更具可读性、更常用的方法来实现这一点,以及在我用丑陋的东西(如
&(**begin)

填充代码后,是否有一些东西会再次困扰我:

#include <memory>

template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
    return p;
}

template <class Pointer>
inline
typename std::pointer_traits<typename std::remove_reference<Pointer>::type>::element_type*
to_raw_pointer(Pointer&& p) noexcept
{
    return ::to_raw_pointer(p.operator->());
}
int main()
{
    std::shared_ptr<int> p1(new int(1));
    int* r1 = to_raw_pointer(p1);
    int* p2 = new int(2);
    int* r2 = to_raw_pointer(p2);
}
#包括
模板
内联
T*
到原始指针(T*p)无异常
{
返回p;
}
模板
内联
typename std::指针\特征::元素\类型*
to_原始_指针(指针和p)无异常
{
return::to_raw_指针(p.operator->());
}
int main()
{
std::共享ptr p1(新int(1));
int*r1=到原始指针(p1);
int*p2=新的int(2);
int*r2=到原始指针(p2);
}

为了增加可读性,您可以创建自己的包装器来取消引用任何(智能)指针:

template auto-raw\u-deref(T)->decltype(&**T){return&**T;}
这会把你的代码变成

template <typename TIterator>
void doSomething(TIterator begin, TIterator end)
{
    std::map<double, decltype(raw_deref(begin))> map;
    ...
    auto firstPointer = raw_deref(begin);
    ...
    functionAcceptingPointer(raw_deref(begin));
    ....
}
模板
无效剂量测定(滴定仪开始,滴定仪结束)
{
地图;
...
自动第一指针=原始数据(开始);
...
函数接收指针(原始数据(开始));
....
}

当然,你可以想出一个比原始文档更好的名字:)

你可以定义模板函数getptr(ptr){return&(**ptr)}并在任何地方使用它来让代码更清晰。“出于某种原因,std::shared_ptr不能隐式转换为Widget*”-无法理解为什么-@borisbn:这就是
操作符*
,它返回一个
小部件&
-而不是一个指针。“出于某种原因”有充分的理由!隐式地将智能指针视为哑指针可能会带来痛苦的后果:
delete mysmartptr;/*没有错误*/@gmannickgGood note。不幸的是,
const
帮不上忙,因为它不能阻止
delete
。哦,这是C++的省略谢谢!因此,如果我解释正确的话,您进行了部分模板专门化,第一个定义在普通指针上调用,第二个定义在智能指针上调用。对,对。只要您的智能指针实现了
操作符->()
,并且符合
指针特性
,您就可以开始了。而
pointer\u traits
的设计使大多数智能指针即使是意外也能符合要求。当
D::pointer
本身就是一个智能指针时,这种设计甚至可以处理
std::unique\ptr
。@HowardHinnant:我会通过引用获取智能指针,这不允许在临时表上调用它。这很好,因为(A)您的代码当前无法使用
unique\u ptr
,以及(B)
to\u raw\u指针
可能会释放指向的对象,因为如果传递一个单独拥有的临时对象,它将返回该对象。@HowardHinnant:从
共享的\u ptr
中减去
1
没有意义,您拥有的对象看起来非常像迭代器,这是一个与讨论的OP非常不同的用例。我不确定在处理迭代器时,使用
到\u raw\u指针是不是一个好主意。“迭代器不是用来抽象指针的吗?@HowardHinnant:我刚刚意识到你是谁:我认为我不会“赢得”这场辩论。我想你最终会向我展示一些我从未想过的魔术或用例。但现在我仍然认为在这里接受右值是不好的。或者两个不同的用例可能有不同的函数名?请注意
decltype(**t)
有一个重载的
运算符(&()
),它不返回实际指针。例如,一个
bit\u引用
类,当您获取它的地址时,它返回类型
bit\u指针
。当然也有一些限制,如果一些自制的智能指针类从
操作符*
返回有趣的东西。我希望OP能意识到这一点,因为他的代码也会遇到同样的问题,所以我只是想让代码更具可读性和表达力。
void functionAcceptingPointer(Widget* widget);

template <typename TIterator>
void doSomething(TIterator begin, TIterator end);
{
    std::map<double, decltype(&(**begin))> map;
    ...
    auto firstPointer = &(**begin);
    ...
    functionAcceptingPointer(&(**begin));
    ....
}
#include <memory>

template <class T>
inline
T*
to_raw_pointer(T* p) noexcept
{
    return p;
}

template <class Pointer>
inline
typename std::pointer_traits<typename std::remove_reference<Pointer>::type>::element_type*
to_raw_pointer(Pointer&& p) noexcept
{
    return ::to_raw_pointer(p.operator->());
}
int main()
{
    std::shared_ptr<int> p1(new int(1));
    int* r1 = to_raw_pointer(p1);
    int* p2 = new int(2);
    int* r2 = to_raw_pointer(p2);
}
template<typename T> auto raw_deref(T t) -> decltype( &**t ) { return &**t; }
template <typename TIterator>
void doSomething(TIterator begin, TIterator end)
{
    std::map<double, decltype(raw_deref(begin))> map;
    ...
    auto firstPointer = raw_deref(begin);
    ...
    functionAcceptingPointer(raw_deref(begin));
    ....
}