c++vectorsmart-pointers

std::vector: when is a pointer not a pointer?


I have this existing working code, which I am trying to convert to implementation:

Bitmap *pbitmap = new Bitmap(L"images.png");
nWidth  = pbitmap->GetWidth();
nHeight = pbitmap->GetHeight();
graphics.DrawImage(pbitmap, 950, 200, nWidth, nHeight);

So I now have this almost equivalent code using (Massive thanks to @heap underrun !!)

//  create empty vector container
std::vector<std::unique_ptr<Gdiplus::Bitmap>> my_vec;
//  instantiate one Bitmap object
my_vec.push_back(std::make_unique<Gdiplus::Bitmap>(L"images.png"));
nWidth  = my_vec[0]->GetWidth(); 
nHeight = my_vec[0]->GetHeight();   
Bitmap *pbitmap = (Bitmap *) my_vec[0];
graphics.DrawImage(pbitmap, 950, 200, nWidth, nHeight);

The GetWidth()/GetHeight() lines appear to confirm that my_vec[0] is a Bitmap* ... but the following assignment line fails with the following error:

example1.cpp:143:22: error: invalid cast from type '__gnu_cxx::__alloc_traits<std::allocator<std::unique_ptr<Gdiplus::Bitmap> >, std::unique_ptr<Gdiplus::Bitmap> >::value_type' {aka 'std::unique_ptr<Gdiplus::Bitmap>'} to type 'Gdiplus::Bitmap*'
143 |    Bitmap *pbitmap = (Bitmap *) my_vec[0];

So I still just don't understand how works, and how to utilize it... Advise?


Solution

  • The GetWidth()/GetHeight() lines appear to confirm that my_vec[0] is a Bitmap* ...

    This is not correct. my_vec[0] is not a Bitmap*. It is a std::unique_ptr<Bitmap>.

    ->GetWidth() works with it because std::unique_ptr has an overload for operator-> which allows you to treat it "as if" it was a pointer syntactically when you access members.

    If you want to get the raw pointer, you need to use std::unique_ptr:get():

    Bitmap *pbitmap = my_vec[0].get();
    

    But, keep in mind it is your responsibility to avoid using the pointer you get from get() after the std::unique_ptr is destroyed (and the object it owns is destroyed with it).

    Note:

    The result from get() should better be passed to the function directly, to reduce the chances the pointer is kept around and gets abused (i.e. used after destruction as mentioned above):

    //-----------------vvvvvvvvvvvvvvv-----------------------------
    graphics.DrawImage(my_vec[0].get(), 950, 200, nWidth, nHeight);