我有一些关于使用堆栈与堆的基本问题。那里有很多答案,但我不确定如何将它与下面的内容联系起来。
我认为通过举例说明更容易解释......
做“更好”
struct Widget3 {
Widget3(std::shared_ptr<Widget1> widget1, std::shared_ptr<Widget2> widget2)
: _widget1(std::move(widget1))
, _widget2(std::move(widget2))
{
}
void doSomething()
{
std::cout << _widget1.hello() << _widget2.hello();
}
private:
std::shared_ptr<Widget1> _widget1;
std::shared_ptr<Widget2> _widget2;
};
或者
struct Widget3 {
Widget3(const Widget1 & widget1, const Widget2 & widget2)
: _widget1(widget1)
, _widget2(widget2)
{
}
void doSomething()
{
std::cout << _widget1->hello() << _widget2->hello();
}
private:
Widget1 _widget1;
Widget2 _widget2;
};
第二个例子让我们复制Widget1
和Widget2
,但是我们假设我们在程序开始时创建所有这些对象并且不关心成本(性能和内存)复制对象。
使用第二个示例,其中_widget1
和_widget2
在堆栈中是否更快?
答案 0 :(得分:0)
你的第二种方式更好,因为如果你选择不使用智能指针,就不会有内存泄漏。
但不能保证它会在堆栈上完成。
如果我写了:
Widget1 widget1;
Widget2 widget2;
Widget3 *widget3 = new Widget3(widget1, widget2);
int main(){
// do something with 'widget3'
delete widget3;
}
那么呢?
你应该尽可能不使用指针,它只是更安全。但是,如果您的数据有多个句柄,并且您无法通过引用传递(出于任何疯狂的原因),那么请务必使用示例1。
在这种情况下,哪种方法更好。没有哪种方法始终优于另一种方法。
答案 1 :(得分:0)
首先,这两个Widget3实现是不一样的。 Widget3与shared_ptr的第一个实现将简单地移动指针(不会复制Widget1或Widget2)。但是,第二个实现会将Widget1和Widget2复制到成员变量中。
以下是证据:
#include <iostream>
#include <memory>
namespace
{
std::ostream& os = std::cout;
}
struct Widget1
{
Widget1()
{
os << __FUNCSIG__ << std::endl;
}
Widget1( const Widget1& rhs )
{
os << __FUNCSIG__ << std::endl;
}
Widget1( Widget1&& rhs )
{
os << __FUNCSIG__ << std::endl;
}
};
struct Widget2
{
Widget2()
{
os << __FUNCSIG__ << std::endl;
}
Widget2( const Widget2& rhs )
{
os << __FUNCSIG__ << std::endl;
}
Widget2( Widget2&& rhs )
{
os << __FUNCSIG__ << std::endl;
}
};
struct Widget3_1 {
Widget3_1(std::shared_ptr<Widget1> widget1, std::shared_ptr<Widget2> widget2)
: _widget1(std::move(widget1))
, _widget2(std::move(widget2))
{
}
private:
std::shared_ptr<Widget1> _widget1;
std::shared_ptr<Widget2> _widget2;
};
struct Widget3_2 {
Widget3_2(const Widget1 & widget1, const Widget2 & widget2)
: _widget1(widget1)
, _widget2(widget2)
{
}
private:
Widget1 _widget1;
Widget2 _widget2;
};
int main()
{
const int repeatCount = 1;
{
os << " Widget3_1 : " << std::endl;
std::shared_ptr<Widget1> widget1( new Widget1 );
std::shared_ptr<Widget2> widget2( new Widget2 );
Widget3_1(widget1, widget2);
}
{
os << " Widget3_2 : " << std::endl;
Widget1 widget1;
Widget2 widget2;
Widget3_2(widget1, widget2);
}
} // int main
输出:
Widget3_1 :
__thiscall Widget1::Widget1(void)
__thiscall Widget2::Widget2(void)
Widget3_2 :
__thiscall Widget1::Widget1(void)
__thiscall Widget2::Widget2(void)
__thiscall Widget1::Widget1(const struct Widget1 &)
__thiscall Widget2::Widget2(const struct Widget2 &)
您不仅要担心其他事情,我认为它们之间没有任何区别。随着项目规模的扩大,差异可能会增大,但除了测试之外别无他法,以证明究竟发生了什么。为了说服你,让我们给你一些测试结果。这是在VisualC,Windows 8.1
上测试的#include <iostream>
#include <string>
#include <memory>
#include <intrin.h>
namespace
{
std::ostream& os = std::cout;
typedef decltype(__rdtsc()) ClockType;
ClockType clock;
void MeasureBegin()
{
clock = __rdtsc();
}
ClockType MeasureEnd()
{
return __rdtsc() - clock;
}
}
struct Widget1
{
Widget1()
: a(0),b(1),c(2),d(3)
{
}
int a,b,c,d;
};
struct Widget2
{
Widget2()
:j ("Hello, World")
{
}
std::string j;
};
struct Widget3 {
Widget3(const Widget1 & widget1, const Widget2 & widget2)
: _widget1(widget1)
, _widget2(widget2)
{
}
private:
Widget1 _widget1;
Widget2 _widget2;
};
int main()
{
const int testCount = 10;
const int repeatCount = 100000;
ClockType c = 0;
for( int j = 0; j < testCount; ++j )
{
Widget1 widget1;
Widget2 widget2;
MeasureBegin();
for (int i = 0; i < repeatCount; ++i)
{
Widget3(widget1, widget2);
}
c = MeasureEnd();
std::cout << " 1 : " << c << std::endl;
Widget1* pwidget1 = new Widget1();
Widget2* pwidget2 = new Widget2();
MeasureBegin();
for (int i = 0; i < repeatCount; ++i)
{
Widget3(*pwidget1, *pwidget2);
}
c = MeasureEnd();
std::cout << " 2 : " << c << std::endl;
delete pwidget1;
delete pwidget2;
}
} // int main
输出:
1 : 5030133
2 : 5726116
1 : 4898262
2 : 5915359
1 : 4805982
2 : 4988638
1 : 4758595
2 : 5065566
1 : 5470122
2 : 5312685
1 : 5133652
2 : 5753500
1 : 5475479
2 : 5196111
1 : 5153481
2 : 5678220
1 : 4790526
2 : 4820254
1 : 4836252
2 : 5231158
没有区别。