C++ std::shared_ptr或std::unique_ptr赋值运算符重载

C++ std::shared_ptr或std::unique_ptr赋值运算符重载,c++,shared-ptr,smart-pointers,unique-ptr,C++,Shared Ptr,Smart Pointers,Unique Ptr,我看不出为什么它们没有为它们模板化到的类型的普通旧指针提供赋值运算符重载。如果让智能指针接口尽可能接近普通的旧指针的目标,那么为什么它们不让赋值操作符像这样过载呢 inline std::shared_ptr<type> &operator=( const type * pointer) { reset(a); } inline std::shared_ptr&operator=(常量类型*指针) { 重置(a); } 这样,您可以像使用普通指针一样使用它们,如下

我看不出为什么它们没有为它们模板化到的类型的普通旧指针提供赋值运算符重载。如果让智能指针接口尽可能接近普通的旧指针的目标,那么为什么它们不让赋值操作符像这样过载呢

inline std::shared_ptr<type> &operator=( const type * pointer)
{
    reset(a);
}
inline std::shared_ptr&operator=(常量类型*指针)
{
重置(a);
}
这样,您可以像使用普通指针一样使用它们,如下所示:

std::shared_ptr<int> test = new int;
std::shared_ptr test=new int;
这根本不是一个问题,只是想知道为什么他们会麻烦地让几个操作符超载

还想知道是否有办法让全局赋值操作符重载来完成此操作,或者是否有任何理由我不应该这样做

编辑:在此处添加对Nawaz关于代码格式的回答的回复。我只是写了这个测试程序来看看你说的是否正确:

template<class T>
class peh
{
public:
    peh() {meh = 3;}
    const peh<T> & operator=(const int * peh)
    {
    }
};

void f( peh<int> teh)
{

}

int main()
{
    int * meh = new int;

    f(meh);

    system("PAUSE");
    return 0;
}
模板
类peh
{
公众:
peh(){meh=3;}
常量peh和运算符=(常量int*peh)
{
}
};
空位f(北德)
{
}
int main()
{
int*meh=新int;
f(兆欧);
系统(“暂停”);
返回0;
}
这里的错误是,没有从
peh
int*
的可用转换。那么,为什么可以将
std::shared_ptr
转换为
int*

还想知道是否有办法让全局赋值操作符重载来完成此操作,或者是否有任何理由我不应该这样做

否。赋值运算符重载必须是成员函数

顺便说一下,如果您想要以下功能,那么您不应该谈论赋值运算符,而是应该问:为什么将原始指针作为参数的构造函数是显式的?为什么不含蓄

//this code requires an implicit constructor, not assignment!
std::shared_ptr<int> test = new int;  //illegal 
//此代码需要隐式构造函数,而不是赋值!
标准::共享测试=新整数//非法的
这是非法的,但假设有一段时间这是允许的,那么您可以调用以下函数,并将原始指针作为参数传递:正如回答的其余部分所解释的那样,这样的功能将是危险的(阅读注释):

void f(标准::共享测试)
{
//代码
}//测试将在此处被销毁(当它超出范围时)
//如果test.use_count()==1,则它管理的指针
//也会被摧毁。(请注意这一点)
现在看看危险的部分:

int*ptr=newint;
f(ptr);
//请注意,如果允许,则可以调用f:
//标准::共享测试=新整数;
//就好像ptr被分配给了参数:
//标准::共享测试=ptr;
//问题:现在f()中发生了什么?
//答:在f()内,test(共享的ptr)将推断没有其他人
//指它包含的指针,因为test.use_count()==1
//在这种情况下,测试显然是错误的,因为它无法证明这一点!
//危险
*ptr=10//未定义的行为,因为ptr被共享的ptr删除

请阅读评论。它解释了上面代码片段的每个部分。

您显示的
操作符=
实际上不会启用您想要的语法<代码>共享\u ptr p=新整数将使用来自T*的共享\u ptr构造函数和共享\u ptr的复制构造函数。shared_ptr具有这两种功能,但您的语法不起作用,因为T*中的构造函数是显式的

这是因为如果该构造,
std::shared\u ptr test=new int,可以隐式完成。这意味着共享的\u ptr可以获得指针的所有权,而无需任何人明确要求。Nawaz指出了一个很容易出错的原因;您必须非常小心,您正在使用的指针不会突然在您不知情的情况下被某个共享的ptr采用,然后从您的下方被销毁

下面的示例显示了这种危险的隐式构造:

#include <iostream>

template<typename T>
struct owning_pointer {
    T *t;
    owning_pointer(T *t) : t{t} {}
    ~owning_pointer() {
        std::cout << t << " deleted\n";
        delete t;
    }
};

void foo(owning_pointer<int> thief) {}

int main() {
    int *i = new int;
    std::cout << i << " allocated\n";
    foo(i);
}
并查看将
explicit
添加到所属的\u ptr构造函数时出现的错误。我得到:

main.cpp:18:5: error: no matching function for call to 'foo'
    foo(i);
    ^~~
main.cpp:13:6: note: candidate function not viable: no known conversion from 'int *' to 'owning_pointer<int>' for 1st argument;
void foo(owning_pointer<int> thief) {}
     ^
operator=
将启用以下功能:

shared_ptr<int> s;
s = new int;
shared_ptr s;
s=新整数;

这看起来不像从t*隐式构造shared_ptr那样容易出错,但我也看不出它真的有任何价值。

为什么调用void f()error不会出错?std::share_ptr和int*是完全不同的类型。@FatalCatharsis:因为它是允许的,如果
std::shared_ptr test=new int是允许的。@Nawaz:在我的主要问题中添加了一条回复注释。Nawaz:比这更糟糕。如果函数被声明为
void f(const std::shared\u ptr&test)
@MartinBonner,它也会失败(以完全相同的方式)。什么比什么更糟糕?没有全局赋值运算符。赋值运算符只能作为成员函数重载。@BenjaminLindley:我想他是在说为什么它不是成员函数,因为他想写
std::shared\u ptr test=new int
@Nawaz:读他的最后一句话。@BenjaminLindley:Ohh..让我编辑我的答案。另外,重载赋值运算符将不允许构造
std::shared\u ptr test=new int,它需要隐式构造函数。它将允许
std::shared\u ptr测试;测试=新的整数我实际上是这样构造我的指针的,实际上是当它在声明和定义之间分开时,我才想这样做。当我过去在类(
int*m_-meh
)中声明成员指针时,我会在构造函数中定义
m_-meh=new int,你必须声明你是智能指针(
std::shared_ptr m_meh
),然后在构造函数中调用reset(
m_meh.reset(new int
);我猜语法只是把我弄错了方向。定义没有使用赋值运算符。但是,它都能工作
0x10d400880 allocated
0x10d400880 deleted
main.cpp:18:5: error: no matching function for call to 'foo'
    foo(i);
    ^~~
main.cpp:13:6: note: candidate function not viable: no known conversion from 'int *' to 'owning_pointer<int>' for 1st argument;
void foo(owning_pointer<int> thief) {}
     ^
std::shared_ptr<int> test(new int); // one extra character isn't a hardship. I typically prefer () construction anyway.
std::shared_ptr<int> test{new int}; // although I might start preferring {} construction in C++11
auto test = std::make_shared<int>(); // this is slightly different in that the allocated int is zero-initialized
struct foo {
    std::shared_ptr<int> m_meh;
    foo()
      : m_meh(new int)
    {
        // no need for m_meh.reset(new int) here
    }
};
shared_ptr<int> s;
s = new int;