0

Considering the following example:

#include <wx/bitmap.h>

int main()
{
    wxBMPHandler h;

    wxImage::AddHandler(&h);

    wxBitmap bm = wxBitmap(200, 200);
    bm.SaveFile("file.bmp", wxBITMAP_TYPE_BMP);

    return 0;
}

Since I'm only using h to call AddHandler() and not for anything else, I'd like to avoid defining it altogether and do the whole thing in one line. So I thought about replacing that with:

wxImage::AddHandler(&wxBMPHandler());

which compiles fine, but calling SaveFile() won't work then; WxWidgets will present an error stating "No image handler for type 1 defined" at runtime.

I guess the object created inside the function call is temporary, but I'm not sure about that. If not, what am I missing, and how can I avoid defining h?

It's worth noting that AddHandler() has the following signature:

static void AddHandler( wxImageHandler *handler );



[Update] In response to M.M's comment saying:

wxImage::AddHandler(&wxBMPHandler()); should fail to compile, unless that class has overloaded operator& for rvalues

Since I couldn't find a definition for operator& in WxWidgets' source code, I created this test project:

#include <iostream>
#include <string>

using namespace std;

string* address = nullptr;

void testing(string* input)
{
    *input = "Something else entirely";
    address = input;
}

int main()
{
    testing(&string("Life is a test"));

    cout << *address << endl;

    cin.get();
    return 0;
}

It compiles fine, and runs without any "hard error" - the only caveat is that nothing is shown in the screen - (*address).empty() returns true. I even defined my own class to test with, instead of std::string and yielded the same behavior (no compiler error, no runtime error, but no output).

I also tried this one-liner, as suggested by aichao, without success:

wxImage::AddHandler(shared_ptr<wxBMPHandler>(new wxBMPHandler()).get());
Community
  • 1
  • 1
Marc.2377
  • 7,807
  • 7
  • 51
  • 95
  • 1
    To make it one line, you need to create it on the heap and make it a shared_ptr. Otherwise, temp variable goes out of scope. – aichao Jul 27 '16 at 23:39
  • `wxImage::AddHandler(&wxBMPHandler());` should fail to compile, unless that class has overloaded `operator&` for rvalues – M.M Jul 27 '16 at 23:41
  • @aichao Could you specify how? I tried `wxImage::AddHandler(shared_ptr(new wxBMPHandler()).get());` - it didn't work as well. – Marc.2377 Jul 28 '16 at 05:31
  • @M.M hmm, I'm not sure about that. See my update to the question body. – Marc.2377 Jul 28 '16 at 06:16
  • @Marc.2377 sorry, I forgot to add that wxImage::AddHandler itself needs to be modified to have the shared_ptr as input, which is not possible. – aichao Jul 28 '16 at 09:59
  • @Marc.2377 the code you posted [has an error](https://godbolt.org/g/VZnHEx), if your compiler is not detecting it then something's wrong – M.M Jul 28 '16 at 10:05
  • @Marc.2377 my first comment was not meant to be an answer. Otherwise, I would have answered. My points (if you are to make it a one-liner, which I suggest you not) were: (i) to avoid the dangling pointer the object needs to be allocated on the heap, and (ii) to avoid a resource leak, the pointer to the object needs to be a `shared_ptr`. To actually implement these points, you can wrap `wxImage::AddHandler` in another function that accepts the `shared_ptr` as input and forwards the pointer via `get()` to `wxImage::AddHandler`. If you want to see that as an answer, let me know. – aichao Jul 28 '16 at 10:42
  • @Marc.2377 I'll correct myself again. Looking at the [wxWidgets docs here](http://docs.wxwidgets.org/trunk/classwx_image.html#ab39fb3747dfb8c2d444eff9fe41fa205), you do not need to manage the memory for the handlers, `wxWidgets` will do that for you. See `wxImage::AddHandler` and `wxImage::CleanUpHandlers`. Therefore, you should be able to just allocate the handler on the heap with `new` as a one-liner. – aichao Jul 28 '16 at 11:16
  • @M.M "The -fpermissive flag causes the compiler to report some things that are actually errors (but are permitted by some compilers) as warnings" [source](http://stackoverflow.com/a/8843846/3258851). Indeed it doesn't compile with GCC, but I was using the latests MSVC, with warnings set to the highest level! – Marc.2377 Jul 28 '16 at 20:31
  • 1
    you'd have to consult MSVC documentation for the behaviour of `&wxBMPHandler()` then – M.M Jul 29 '16 at 12:29

2 Answers2

3

I've never used wxWidgets before, but according to the wxWidgets version 3.1.1 API docs here, you should call wxImage::AddHandler using a heap-allocated handler object:

wxImage::AddHandler(new wxBMPHandler);

Therefore, there is no need for defining h. Also according to the docs, the memory for this handler object is managed by the wxWidgets framework. Specifically, the docs says that the handler is a

heap-allocated handler object which will be deleted by wxImage if it is removed later by RemoveHandler() or at program shutdown.

There is also the static member function wxImage::CleanUpHandlers() to delete all registered image handlers. According to the docs:

This function is called by wxWidgets on exit.

Therefore, you do not have to delete the handler yourself unless you specifically want to (i.e., to free up some memory).

Hope this helps.

aichao
  • 7,375
  • 3
  • 16
  • 18
  • @Marc.2377 In fact, I'm surprised that you did not run into a problem on program exit with your original code when `wxImage::CleanUpHandlers()` is called. See this [SO question/answer](http://stackoverflow.com/questions/4355468/is-it-possible-to-delete-a-non-new-object) for why. Which compiler are you using? – aichao Jul 28 '16 at 12:59
  • This is great, thanks. I was testing with MSVC 2015 Update 3 btw; using the highest warning level and SDL checks enabled. – Marc.2377 Jul 28 '16 at 19:56
1

In wxImage::AddHandler(&wxBMPHandler());, the lifetime of the temporary stop at the end of the expression, so you have dangling pointer.

In

wxBMPHandler h;

wxImage::AddHandler(&h);

wxBitmap bm = wxBitmap(200, 200);
bm.SaveFile("file.bmp", wxBITMAP_TYPE_BMP);

h outlives the call bm.SaveFile("file.bmp", wxBITMAP_TYPE_BMP);.

You will have similar issue with

{
    wxBMPHandler h;

    wxImage::AddHandler(&h);
} // End of life time of h

wxBitmap bm = wxBitmap(200, 200);
bm.SaveFile("file.bmp", wxBITMAP_TYPE_BMP);
Jarod42
  • 203,559
  • 14
  • 181
  • 302