2015-10-04 79 views
3

我想了解在現代C++中使用智能指針,並且我寫了一個小的,簡單的程序來測試valgrind。問題是,下面的例子:valgrind和std :: unique_ptr --- false positive or not?

#include <iostream> 
#include <memory> 

class Base { 
    private: 
     virtual double meth_1(double x) const = 0; 
     virtual void meth_2(int y) const = 0; 
    protected: 
     Base() 
     { 
      std::cout << "ctor of base for: " << this << std::endl; 
     } 
    public: 
     virtual ~Base() 
     { 
      std::cout << "dtor of base for: " << this << std::endl; 
     } 
     double IMeth_1(double x) const 
     { 
      return meth_1(x); 
     } 
     void IMeth_2(int y) const 
     { 
      meth_2(y); 
     } 
}; 

class Derived_1 : public Base { 
    private: 
     double meth_1(double x) const final 
     { 
      return x + 5.0; 
     } 
     void meth_2(int y) const final 
     { 
      std::cout << (y + 5) << std::endl; 
     } 
    public: 
     Derived_1() : Base() 
     { 
      std::cout << "ctor of Derived_1: " << this << std::endl; 
     } 
     ~Derived_1() 
     { 
      std::cout << "dtor of Derived_1: " << this << std::endl; 
     } 
}; 

class Derived_2 : public Base { 
    private: 
     double meth_1(double x) const final 
     { 
      return x + 10.0; 
     } 
     void meth_2(int y) const final 
     { 
      std::cout << (y + 10) << std::endl; 
     } 
    public: 
     Derived_2() : Base() 
     { 
      std::cout << "ctor of Derived_2: " << this << std::endl; 
     } 
     ~Derived_2() 
     { 
      std::cout << "dtor of Derived_2: " << this << std::endl; 
     } 
}; 

void Fun(const Base& crBase) 
{ 
    crBase.IMeth_2(5); 
} 

int main(int argc, char* argv[]) { 
    std::unique_ptr<Base> upBase; 

    for (std::size_t idx = 0ul; idx < 2ul; idx++) { 
     upBase  = std::make_unique<Derived_1>(); 
     std::cout << upBase->IMeth_1(idx) << std::endl; 
     upBase->IMeth_2(idx); 
     std::cout << "----------"    << std::endl; 
    } 

    for (std::size_t idx = 0ul; idx < 2ul; idx++) { 
     upBase  = std::make_unique<Derived_2>(); 
     std::cout << upBase->IMeth_1(idx) << std::endl; 
     upBase->IMeth_2(idx); 
     std::cout << "----------"    << std::endl; 
    } 

    upBase = std::make_unique<Derived_1>(); 
    Fun(*upBase); 

    return 0; 
} 

給出了一個內存泄漏時valgrind --leak-check=full --show-leak-kinds=all <prog_name>運行:

==32350== HEAP SUMMARY: 
==32350==  in use at exit: 72,704 bytes in 1 blocks 
==32350== total heap usage: 6 allocs, 5 frees, 72,744 bytes allocated 
==32350== 
==32350== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1 
==32350== at 0x4C28C10: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==32350== by 0x4EBE1EF: pool (eh_alloc.cc:117) 
==32350== by 0x4EBE1EF: __static_initialization_and_destruction_0 (eh_alloc.cc:244) 
==32350== by 0x4EBE1EF: _GLOBAL__sub_I_eh_alloc.cc (eh_alloc.cc:307) 
==32350== by 0x400F279: call_init.part.0 (in /usr/lib/ld-2.22.so) 
==32350== by 0x400F38A: _dl_init (in /usr/lib/ld-2.22.so) 
==32350== by 0x4000DB9: ??? (in /usr/lib/ld-2.22.so) 
==32350== 
==32350== LEAK SUMMARY: 
==32350== definitely lost: 0 bytes in 0 blocks 
==32350== indirectly lost: 0 bytes in 0 blocks 
==32350==  possibly lost: 0 bytes in 0 blocks 
==32350== still reachable: 72,704 bytes in 1 blocks 
==32350==   suppressed: 0 bytes in 0 blocks 
==32350== 
==32350== For counts of detected and suppressed errors, rerun with: -v 
==32350== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

是與72,704字節仍在使用在退出該塊假陽性,還是我誤用智能指針?我假設我沒有做任何形式的切片,因爲每當對象被刪除時都會調用基礎dtor。

對不起,如果這是一個愚蠢的問題,但我找不到在SO中的任何valgrind/false positive/unique_ptr相關主題。此外,我不知道可能在unique_ptr中創建的任何附加塊與shared_ptr類似,以跟蹤該對象。

編輯:不是Still Reachable Leak detected by Valgrind重複,因爲在我的情況,我不使用線程(和valgrind衆所周知,產生假陽性的,特別是環境的openmpi)。此外,在另一個問題中,通過對所提供的代碼進行適當修改來解決問題。不過,沒有什麼調用真實記憶任何共識泄漏 ---也就是說,應該是在出口仍在使用是可達塊被視爲內存泄漏,還是不行。

+0

看起來像Valgrind的錯誤,它的檢測自身分配...您'的std :: unique_ptr'的使用看起來不錯。 – Quentin

+1

看着代碼看起來不錯,但你應該嘗試減少它,因爲在這裏似乎還有相當多的不必要的代碼來重現問題。作爲在valgrind中測試小事情的一般規則,將整個測試放入一個函數中並多次調用它。然後,如果丟失塊的數量增加,你知道你有一個真正的內存泄漏。 – Dave

+0

謝謝你們兩位的評論。我會嘗試這個函數的方法來查看在出口處使用的塊是否增加或保持不變,@Dave。 –

回答

6

這不是一個valgrind錯誤。這是一個libstdC++特定功能, 是在http://gcc.gnu.org/viewcvs/gcc?view=revision&revision=219988中引入的。

如果你看看代碼,你會發現libstdC++ - v3/libsupC++/eh_alloc.cc中的類池沒有析構函數,因爲它是一個緊急內存池,用於在整個運行時一個應用程序。

即使是最小的程序說明問題了:

~ % echo "int main() {}" | g++ -x c++ - 
~ % valgrind --leak-check=full --show-leak-kinds=all ./a.out 
==502== Memcheck, a memory error detector 
==502== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. 
==502== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info 
==502== Command: ./a.out 
==502== 
==502== 
==502== HEAP SUMMARY: 
==502==  in use at exit: 72,704 bytes in 1 blocks 
==502== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated 
==502== 
==502== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1 
==502== at 0x402CC6F: malloc (vg_replace_malloc.c:299) 
==502== by 0x40F420F: _GLOBAL__sub_I_eh_alloc.cc (in /usr/lib64/gcc/x86_64-pc-linux-gnu/5.2.1/libstdc++.so.6.0.21) 
==502== by 0x4010AA4: call_init.part.0 (dl-init.c:72) 
==502== by 0x4010D44: call_init (dl-init.c:30) 
==502== by 0x4010D44: _dl_init (dl-init.c:120) 
==502== by 0x4000C79: ??? (in /lib64/ld-2.22.90.so) 
+5

如果這是真的,我認爲這仍然會使它成爲valgrind錯誤。 valgrind應該有一個抑制列表,以便知道誤報 - 來自標準庫的分配不會真正指示正在測試的應用程序中存在任何內存泄漏 - 不會被警告。基於你的回答,似乎是壓制列表中缺少一個條目。 – hvd

+0

明天如果缺少析構函數是真的有意的話,我會問明天該代碼的作者。 – octoploid

+0

[在公關中已經指出,導致您鏈接到的變化。](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64535)而簡短的回答:這很棘手,有角落案件要考慮。 – hvd