2

我看不出为什么这些没有为它们模板化的类型的普通旧指针的赋值运算符重载的原因。如果使智能指针接口尽可能接近普通旧指针的目标,那么他们为什么不像这样为赋值运算符进行重载呢?

inline std::shared_ptr<type> &operator=( const type * pointer)
{
    reset(a);
}

这样你就可以像使用普通指针一样使用它们,如下所示:

std::shared_ptr<int> 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<int>to的可用转换int *。那么为什么 to 可以接受std::shared_ptr<int>int *

4

2 回答 2

5

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

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

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

//this code requires an implicit constructor, not assignment!
std::shared_ptr<int> test = new int;  //illegal 

这是非法的,但假设有一段时间这是允许的,那么您将能够调用以下函数,将原始指针作为参数传递:这样的功能将是危险的,正如答案的其余部分所解释的那样(阅读评论) :

void f(std::shared_ptr<int> test)
{
     //code

} //test will be destructed here  (when it goes out of scope)
  //if test.use_count() == 1, then the pointer which it manages 
  //will be destructed as well. (NOTE THIS POINT)

现在看看危险的部分:

int *ptr = new int;

f(ptr); 
//note that calling f is allowed if it is allowed:
//std::shared_ptr<int> test = new int;
//it is as if ptr is assigned to the parameter:
//std::shared_ptr<int> test = ptr;

//Question : now what happened in f()?
//Answer : inside f(), test (the shared_ptr) will infer that no one else
//refers to the pointer it contains, because test.use_count() == 1
//test is obviously wrong in this case, because it cannot prove that!

//DANGER
*ptr = 10; //undefined behavior, because ptr is deleted by the shared_ptr

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

于 2012-07-01T15:41:27.690 回答
2

您显示的operator=内容实际上不会启用您想要的语法。shared_ptr<int> p = new int;将使用来自 T* 的 shared_ptr 的构造函数和 shared_ptr 的复制构造函数。shared_ptr 两者都有,但你的语法不起作用,因为 T* 的构造函数是explicit.

这样做的原因是,如果该构造 ,std::shared_ptr<int> test = new int;可以隐式完成,则意味着 shared_ptr 可以在没有任何人明确要求的情况下获得指针的所有权。Nawaz 给出了一个非常容易出错的原因。您必须非常小心,您正在使用的指针不会在您不知情的情况下突然被某处的 shared_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);
}

输出将类似于:

0x10d400880 allocated
0x10d400880 deleted

explicit并查看添加到 owning_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) {}
     ^

此外,没有必要允许从 T* 进行隐式构造,因为已经有一些非常简单的分配方法,而不会产生同样的错误可能性:

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

如果您正在初始化一个成员 shared_ptr 那么您可以在初始化列表中初始化它,而不是使用赋值或reset()在构造函数的主体中:

struct foo {
    std::shared_ptr<int> m_meh;
    foo()
      : m_meh(new int)
    {
        // no need for m_meh.reset(new int) here
    }
};

可以实现的是operator=

shared_ptr<int> s;
s = new int;

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

于 2012-07-01T16:04:04.037 回答