我写了一些基准代码(从this blog post扩展代码关于C 03上的C 11移动语义改进),似乎向量< unique_ptr< X>>为1,500,000个项目向量提供更好的性能.事实上,在装有windows 7 64位,Intel Core i5四核cpu和8 GB RAM的PC上,我得到了以下结果(test.exe 1500):
> vector< unique_ptr< MyObject>>:1.5秒@H_419_5@> vector< shared_ptr< MyObject>>:1.6秒@H_419_5@> vector< MyObject>:1.8秒
因此,在C 03(其中std :: unique_ptr不可用)中,似乎最佳选择是vector< shared_ptr< X>> ;;而在C 11中,支持move-semantics的std :: unique_ptr似乎提供了最好的结果.
我在这里错过了什么吗?这是一个很好的C指南,在大向量中,最好将(智能)指针存储到类实例而不是类实例本身吗?
基准代码如下:
//////////////////////////////////////////////////////////////////////////////////// Test vector<X> vs. vector<unique_ptr<X>> vs. vector<shared_ptr<X>>.//// Original benchmark code from:// http://blogs.msdn.com/b/vcblog/archive/2009/06/23/stl-performance.aspx//////////////////////////////////////////////////////////////////////////////////#include <exception> // std::invalID_argument#include <iostream> // std::cout#include <memory> // std::shared_ptr,std::unique_ptr#include <ostream> // std::endl#include <stdexcept> // std::exception#include <string> // std::wstring#include <utility> // std::move#include <vector> // std::vector#include <windows.h> // Win32 Platform SDK (high performance counters,etc.)using namespace std;// Measure time.class Stopwatch{public: Stopwatch() : m_start(0),m_finish(0) { } static voID PerfStartup() { // to confine the test to run on a single processor // in order to get consistent results for all tests. SetThreadAffinityMask(GetCurrentThread(),1); SetThreadIDealProcessor(GetCurrentThread(),0); Sleep(1); } voID Start() { m_finish = 0; m_start = Counter(); } voID Stop() { m_finish = Counter(); } // Elapsed time,in seconds double elapsedtime() const { return (m_finish - m_start) * 1.0 / Frequency(); } voID reset() { m_start = m_finish = 0; }private: long long m_start; long long m_finish; static long long Counter() { LARGE_INTEGER li; queryPerformanceCounter(&li); return li.QuadPart; } static long long Frequency() { LARGE_INTEGER li; queryPerformanceFrequency(&li); return li.QuadPart; }// Ban copyprivate: Stopwatch(const Stopwatch&); Stopwatch& operator=(const Stopwatch&);};// Measure execution time of a block of code.class ScopedStopwatch{public: ScopedStopwatch() { m_sw.Start(); } ~ScopedStopwatch() { m_sw.Stop(); cout << "Elapsed time: " << m_sw.elapsedtime() << " sec" << endl; }private: Stopwatch m_sw; ScopedStopwatch(const ScopedStopwatch&); ScopedStopwatch& operator=(const ScopedStopwatch&);};// User defined Typeclass MyObject{public: wstring name; wstring address; wstring telephone; wstring name2; wstring address2; wstring telephone2; // Default constructor MyObject() { } // copy Constructor MyObject(const MyObject& other) : name(other.name),telephone(other.telephone),address(other.address),name2(other.name2),telephone2(other.telephone2),address2(other.address2) { } // copy assignment operator MyObject& operator=(const MyObject& other) { if (this != &other) { name = other.name; telephone = other.telephone; address = other.address; name2 = other.name2; telephone2 = other.telephone2; address2 = other.address2; } return *this; } // Move constructor MyObject(MyObject&& other) : name(move(other.name)),telephone(move(other.telephone)),address(move(other.address)),name2(move(other.name2)),telephone2(move(other.telephone2)),address2(move(other.address2)) { } // Move assignment operator MyObject& operator=(MyObject&& other) { if (this != &other) { name = move(other.name); telephone = move(other.telephone); address = move(other.address); name2 = move(other.name2); telephone2 = move(other.telephone2); address2 = move(other.address2); } return *this; }};MyObject MakeTestObject(){ MyObject obj; obj.name = L"Stephan T. Lavavej Stephan T. Lavavej Stephan T. Lavavej"; obj.telephone = L"314159265 314159265 314159265 314159265 314159265"; obj.address = L"127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0"; obj.name2 = L"Mohammad Usman. Mohammad Usman. Mohammad Usman. "; obj.telephone2 = L"1234567890 1234567890 1234567890 1234567890 1234567890"; obj.address2 = L"Republik Of mancunia. Republik Of mancunia Republik Of mancunia"; return obj;}unique_ptr<MyObject> MakeUniqueTestObject(){ unique_ptr<MyObject> obj( new MyObject() ); obj->name = L"Stephan T. Lavavej Stephan T. Lavavej Stephan T. Lavavej"; obj->telephone = L"314159265 314159265 314159265 314159265 314159265"; obj->address = L"127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0"; obj->name2 = L"Mohammad Usman. Mohammad Usman. Mohammad Usman. "; obj->telephone2 = L"1234567890 1234567890 1234567890 1234567890 1234567890"; obj->address2 = L"Republik Of mancunia. Republik Of mancunia Republik Of mancunia"; return obj;}shared_ptr<MyObject> MakeSharedTestObject(){ auto obj = make_shared<MyObject>(); obj->name = L"Stephan T. Lavavej Stephan T. Lavavej Stephan T. Lavavej"; obj->telephone = L"314159265 314159265 314159265 314159265 314159265"; obj->address = L"127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0 127.0.0.0"; obj->name2 = L"Mohammad Usman. Mohammad Usman. Mohammad Usman. "; obj->telephone2 = L"1234567890 1234567890 1234567890 1234567890 1234567890"; obj->address2 = L"Republik Of mancunia. Republik Of mancunia Republik Of mancunia"; return obj;}voID Test(int count){ Stopwatch::PerfStartup(); cout << "Inserting " << count << " items in vector.\n"; cout << "\nTesting vector<MyObject>\n"; { ScopedStopwatch sw; vector<MyObject> v; for (int i = 0; i < count; i++) { v.push_back(MakeTestObject()); } } cout << "\nTesting vector<unique_ptr<MyObject>>\n"; { ScopedStopwatch sw; vector<unique_ptr<MyObject>> v; for (int i = 0; i < count; i++) { v.push_back(MakeUniqueTestObject()); } } cout << "\nTesting vector<shared_ptr<MyObject>>\n"; { ScopedStopwatch sw; vector<shared_ptr<MyObject>> v; for (int i = 0; i < count; i++) { v.push_back(MakeSharedTestObject()); } }}int main(int argc,char * argv[]){ static const int kExitOk = 0; static const int kExitError = 1; try { if (argc != 2) { throw invalID_argument("Bad Syntax. Pass insertion count (x 1,000)."); } const int countK = atoi(argv[1]); Test(countK * 1000); return kExitOk; } catch (const exception & e) { cerr << "*** ERROR: " << e.what() << endl; return kExitError; }}////////////////////////////////////////////////////////////////////////////////解决方法 在C 11中,如果您没有使用启用移动的对象,那么您应该使用std :: unique_ptr< T>的向量.来自#include< memory>.的std ::的unique_ptr< T>重量较轻,具有与std :: shared_ptr< T>相似的语义.但在一个重要领域有所不同:对象所有权是明确的.在vector的情况下,向量拥有它包含的对象.现在,如果您正在使用启用移动的对象,只需使用对象的向量,因为它通常“足够快”. C 11中所有启用STL的容器都使用了移动语义(即是的,稍慢,但你在生产力方面获益).如果性能是一个问题,你可以回到std :: unqiue_ptr< T>原因如下.
如果您使用的是pre-C 11,则boost :: shared_ptr< T>并不是你可以做的更糟糕的事情,并且可能是一个适当的过渡路径,直到std :: unique_ptr< T>变得可用.使用boost :: shared_ptr< T>涉及原子增量和指针的赋值.两者都比std :: unique_ptr< T>相当便宜,但更昂贵(和不同的语义).
Move构造函数比移动std :: unique_ptr< T>更昂贵并不让我感到惊讶.因为移动构造函数仍在分配一个对象(即使它的内容/内容被借用,移动,重新定位),而移动一个std :: unique_ptr< T>只是一个整数/指针赋值.使用jemalloc(3)可能会降低Move构造函数的成本,但这只能在* NIX平台上使用.
由于最后一点,基准并不完全是苹果对苹果.如果您正在寻找一致的性能,std :: unique_ptr< T>可能是要走的路(没有分配),但是如果你正在寻找一种“原生”开发习语,这有助于简化开发方法,其中性能不是最重要的方面(即生产力比性能更重要),那么与移动构造函数一起使用普通对象.
总结以上是内存溢出为你收集整理的c – 我们是否应该将智能指针存储到大型std :: vector中的类实例中以获得更好的性能?全部内容,希望文章能够帮你解决c – 我们是否应该将智能指针存储到大型std :: vector中的类实例中以获得更好的性能?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)