使用 std::shared_ptr 接收变量作为参考有哪些优点和缺点?
What are the pros and cons of receiving a variable as a reference with std::shared_ptr?
我只是想知道以下将在 func1
内部创建的指针变量传递给调用者 (func2
) 的方法是否正确。如果这是正确的,它会在返回 func2
时释放内存吗?如果这是个坏主意,那是为什么?
int & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return *d;
}
void func2(){
int & dd = func1();
}
这是一个简化的代码。我假设 d
的大小很大(例如图像)。
添加:
我意识到以下也有效。每种方法的优点和缺点是什么?
std::shared_ptr<int> & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return d;
}
void func2()
{
std::shared_ptr<int> & dd = func1();
}
这两个例子都不好。您不能使用任一 func1
的 return 值,它们始终是悬空引用。
int & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return *d;
} // d is the only owner when it is destroyed, *d is also deleted
std::shared_ptr<int> & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return d;
} // d is destroyed here
I am assuming the size of d
is huge
你错了。 d
指向 的对象的大小与 d
的大小无关,就像原始指针一样。
例如
#include <iostream>
#include <memory>
struct Huge
{
int data[100000];
};
int main()
{
std::cout << sizeof(int) << std::endl
<< sizeof(int*) << std::endl
<< sizeof(std::shared_ptr<int>) << std::endl
<< sizeof(std::unique_ptr<int>) << std::endl
<< sizeof(Huge) << std::endl
<< sizeof(Huge*) << std::endl
<< sizeof(std::shared_ptr<Huge>) << std::endl
<< sizeof(std::unique_ptr<Huge>) << std::endl;
}
for me 结果是
4
8
16
8
400000
8
16
8
I realized that the following also works
如果作品是指 "is accepted by a C++ compiler",那么是的。如果您使用引用 returned,它们都会导致未定义的行为,所以我会明确地说它们 不起作用 .
本想对此做个简单的评论,但实在是太多了。这意味着 mathematician1975 的评论的精确性,我认为这是一个很好的观点。
I thought just returning shared_ptr will require extra cost to copy the control block.
你可能想看看(N)RVO/copy省略,这正是避免这种事情的机制:https://en.cppreference.com/w/cpp/language/copy_elision.
长话短说:返回它不会复制它,而是会在调用者的站点就地构建它。无性能成本!
我制作了一个基本的实时示例,展示了 (N)RVO 的工作原理,可在此处获取:http://coliru.stacked-crooked.com/a/8a32afc3775c685e
编辑:如果它可以帮助阐明所有这些过程,I've written an article 关于复制省略和 [N]RVO。
我只是想知道以下将在 func1
内部创建的指针变量传递给调用者 (func2
) 的方法是否正确。如果这是正确的,它会在返回 func2
时释放内存吗?如果这是个坏主意,那是为什么?
int & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return *d;
}
void func2(){
int & dd = func1();
}
这是一个简化的代码。我假设 d
的大小很大(例如图像)。
添加: 我意识到以下也有效。每种方法的优点和缺点是什么?
std::shared_ptr<int> & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return d;
}
void func2()
{
std::shared_ptr<int> & dd = func1();
}
这两个例子都不好。您不能使用任一 func1
的 return 值,它们始终是悬空引用。
int & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return *d;
} // d is the only owner when it is destroyed, *d is also deleted
std::shared_ptr<int> & func1()
{
std::shared_ptr<int> d = std::make_shared<int>(50);
return d;
} // d is destroyed here
I am assuming the size of
d
is huge
你错了。 d
指向 的对象的大小与 d
的大小无关,就像原始指针一样。
例如
#include <iostream>
#include <memory>
struct Huge
{
int data[100000];
};
int main()
{
std::cout << sizeof(int) << std::endl
<< sizeof(int*) << std::endl
<< sizeof(std::shared_ptr<int>) << std::endl
<< sizeof(std::unique_ptr<int>) << std::endl
<< sizeof(Huge) << std::endl
<< sizeof(Huge*) << std::endl
<< sizeof(std::shared_ptr<Huge>) << std::endl
<< sizeof(std::unique_ptr<Huge>) << std::endl;
}
for me 结果是
4
8
16
8
400000
8
16
8
I realized that the following also works
如果作品是指 "is accepted by a C++ compiler",那么是的。如果您使用引用 returned,它们都会导致未定义的行为,所以我会明确地说它们 不起作用 .
本想对此做个简单的评论,但实在是太多了。这意味着 mathematician1975 的评论的精确性,我认为这是一个很好的观点。
I thought just returning shared_ptr will require extra cost to copy the control block.
你可能想看看(N)RVO/copy省略,这正是避免这种事情的机制:https://en.cppreference.com/w/cpp/language/copy_elision.
长话短说:返回它不会复制它,而是会在调用者的站点就地构建它。无性能成本!
我制作了一个基本的实时示例,展示了 (N)RVO 的工作原理,可在此处获取:http://coliru.stacked-crooked.com/a/8a32afc3775c685e
编辑:如果它可以帮助阐明所有这些过程,I've written an article 关于复制省略和 [N]RVO。