1

I'm building a very basic object loader with DirectX and I decided I wanted to separate its logic from the main portion of my program and put it into its own class (as it probably should be).

The problem I'm having is that my Loader needs access to some of my MainWindow variables such as a DX11 SwapChain to handle the backbuffer for frame rendering.

I'm very new to C++ so I am not sure if I am utilizing pointers efficiently here, but it would be of great help if someone could tell me if what I'm doing is wrong or maybe suggest a more efficient way of handling the problem.

Main Window:

// Global variables
IDXGISwapChain* g_swapChain;  // Pointer to global swap chain 

// Obj loader init example - pass the reference of global swap chain?
ObjectLoader l( &g_swapChain );

// Condensed method call as you don't need to see all parameters
loader.__loadModel("model.obj");

Now, in my ObjectLoader class, what sort of pointer would I set up in order to be able to constantly reference my Main Windows g_swapChain? Am I right in thinking that I should use a double pointer, such as, with the encapsulated class global being a reference to that double pointer.

private: 
IDXGISwapChain& loader_swapChain;

public: 
ObjectLoader::ObjectLoader( IDXGISwapChain** swapChain ) 
{
     loader_swapChain = swapChain;
}

The example below demonstrates where I would need to use MainWindow's swapchain.

ObjectLoader::__loadModel(std::string fielname)
{
     if (modelLoaded)
           ...
     else {
          // this is an example of where I want to use the swap chain in MainWindow
          loader_swapChain->SetFullscreenState(false, NULL);
     }
}

Coming from a Java background, this pointer stuff is giving me headache - hopefully what I am asking makes sense, if not please ask and I will provide more information.

Halfpint
  • 3,967
  • 9
  • 50
  • 92
  • 1
    Ahhrg! Why using that many `*` and `**` if you're using c++ dude? Use reference or value parameters, whenever applicable. – πάντα ῥεῖ Jan 12 '15 at 18:46
  • It seems weird that your model loader is dealing with frame buffer tasks. I think those responsibilities should be separate. – mbgda Jan 12 '15 at 18:46
  • @mbgda I'll take that into consideration - only just started learning DX11, a lot to take in! – Halfpint Jan 12 '15 at 18:48
  • 1
    You might want to look into com_ptr (COM Pointers) as well. This will help eliminate a lot of the *. – user2970916 Jan 12 '15 at 18:48
  • I'll definitely look at them - out of curiosity though, if I wanted to make this work in raw C++ with the demonstrated setup (or even using COM pointers) how would I do this? Have I completely misunderstood the use of them or not? – Halfpint Jan 12 '15 at 18:51
  • @user2970916 Should we really be recommending non-standard solutions to someone new to C++? Why use ComPtr when standard smart pointers exist? – mbgda Jan 12 '15 at 18:52
  • 1
    I agree - model loader should not need to know the back buffer resolution. Also, regarding pointers, D3D and Win32 APIs in general aren't the best examples of how to properly use C++ objects. You will always need to deal with D3D objects as pointers (or wrapped pointers using e.g. `ComPtr`) - you can never have, for example `IDXGISwapChain foo;`. – MooseBoys Jan 12 '15 at 18:53
  • @mbgda this is my point - I have such a basic knowledge that it would be nice to get some correction on my probably obvious mistakes shown above. – Halfpint Jan 12 '15 at 18:53
  • For someone trying to learn DirectX, understanding COM pointers could help understand the way DirectX is structured. – user2970916 Jan 12 '15 at 18:53
  • 1
    @user2970916 - that's a fair point, but the OP doesn't even understand pointers yet, so talking about COM pointers before he understands pointers and smart pointers seems to be a bit premature. – mbgda Jan 12 '15 at 18:54
  • All I understand about COM is that its a resource managed by Windows which can be safely destroyed via a release method. Other than that I'm clueless about their benefits – Halfpint Jan 12 '15 at 18:56
  • 1
    As mgda pointed out, if you do not understand pointers and dynamic memory, and how they are used, it is going to be hard to understand how DirectX is structured in C++. My suggestion would be to first learn how pointers and dynamic memory work in C++. Coming from Java, pointers is quite a steep learning curve. – user2970916 Jan 12 '15 at 18:59
  • You can google "Microsoft Component Object Model" to get an idea what it is and why it exists. ComPtrs are very useful, but only in specific cases - don't go around using them in place of just any kind of pointer. – mbgda Jan 12 '15 at 18:59
  • 1
    Is the name `__loadModel` required by DirectX? It's a [reserved name](http://stackoverflow.com/q/228783/981959) so you must not define your own types/functions/variables with a name like that. – Jonathan Wakely Jan 12 '15 at 19:01
  • @JonathanWakely great point - thank-you. I had no idea `__` was reserved – Halfpint Jan 12 '15 at 19:02
  • @mbgda COM pointers have their own special rules. Using standard smart pointers will generate lots of bugs. – Mark Ransom Jan 12 '15 at 19:07
  • @MarkRansom Sorry, I realize it looks like I was recommending to wrap his D3D pointer in a smart pointer - that's not what I meant - I clarified in a later comment that I didn't want OP to think COM pointers were a generic pointer solution. – mbgda Jan 12 '15 at 19:08
  • 1
    ``Microsoft::WRL::ComPtr`` solves this all nicely... – Chuck Walbourn Jan 12 '15 at 19:15
  • Also, the question title says "output parameters" ... what output parameters? You're not passing an argument in order to get a result back again. – Jonathan Wakely Jan 12 '15 at 19:21

2 Answers2

2

You mixing references and pointers, it won't compile.

I don't think pointer to pointer is really needed.

You can do it like this with reference:

private: 
ID3D11SwapChain& loader_swapChain;

public: 
ObjectLoader::ObjectLoader( ID3D11SwapChain& swapChain ) : loader_swapChain( swapChain )
{
}

or if you want to use pointer:

private: 
ID3D11SwapChain* loader_swapChain;

public: 
ObjectLoader::ObjectLoader( ID3D11SwapChain* swapChain ) : loader_swapChain( swapChain )
{
}

EDIT

if the meaning is to change the global pointer after inited, than a pointer to pointer is possible solution.

a pointer to pointer version:

private: 
ID3D11SwapChain** loader_swapChain;

public: 
ObjectLoader::ObjectLoader( ID3D11SwapChain** swapChain ) : loader_swapChain( swapChain )
{
}

Note that a global variable is not so good solution, better use a singleton.

SHR
  • 7,940
  • 9
  • 38
  • 57
  • 1
    Please note that if you go this route, you cannot construct your ObjectLoader until you've initialized g_swapChain. – mbgda Jan 12 '15 at 18:53
  • Neither of your suggestions will work if the intention is for `ObjectLoader` to always refer to `g_swapChain` and if that can change. The reference one will always refer to the thing that `g_swapChain` pointed to initially and the second one makes a copy of the initial value of `g_swapChain`. Neither will be updated if `g_swapChain` changes. – Jonathan Wakely Jan 12 '15 at 18:57
  • this makes total sense - I do not know why I was using the reference operator, I guess I thought that the class global needed to be a reference of the inbound pointer in order for me to use it. – Halfpint Jan 12 '15 at 19:06
  • 1
    @Alex, `&` is not "the reference operator" it's the address-of operator. It gives you the address of something, i.e. gives a pointer **not** a reference. Given `int i=0;` then `int& ref = i;` is a reference that is bound to `i`, and `int* ptr = &i;` is a pointer that points to `i`. Get a book or tutorial on C++ and learn the basics first. – Jonathan Wakely Jan 12 '15 at 19:08
  • @JonathanWakely For what it's worth, I think he was referring to his usage of the reference type declarator in `IDXGISwapChain& loader_swapChain;`, not the address-of operator in `ObjectLoader l( &g_swapChain );` – mbgda Jan 12 '15 at 19:15
  • @mbgda, aaah ok ... I missed that ... because that's not an operator :) – Jonathan Wakely Jan 12 '15 at 19:20
  • 2
    @JonathanWakely yeah, either way I agree he needs a C++ book immediately :) – mbgda Jan 12 '15 at 19:21
  • Yes I definitely do I've been reading Martin reddys c++ api design but I think I need to get something simpler – Halfpint Jan 12 '15 at 19:27
1
// Global variables
IDXGISwapChain* g_swapChain;  // Pointer to global swap chain 

OK so far.

Is the global swap chain ever changed? That is, do you ever make g_swapChain point to a different chain? Or is it constant once you set it?

// Obj loader init example - pass the reference of global swap chain?
ObjectLoader l( &g_swapChain );

This is a "reference" in one sense, but it's not a C++ "reference" (you're taking the address of something, so you're forming a pointer) so it's best to avoid using the term reference ambiguously.

private: 
IDXGISwapChain& loader_swapChain;

public: 
ObjectLoader::ObjectLoader( IDXGISwapChain** swapChain ) 
{
     loader_swapChain = swapChain;
}

This can't possibly work, firstly, that's not how you set a reference member variable. Reference members must be initialized in the class mem-initializer-list not by assigning something to them. As written, you don't initialize the reference (so it will not compile) and then you try to assign something to the target of the reference (you can't "re-seat" a reference, so assigning to one doesn't change what it refers to, it assigns to the thing it refers to).

So initializing a reference member must be done like:

ObjectLoader::ObjectLoader( IDXGISwapChain** swapChain ) 
: loader_swapChain(swapChain)
{ }

However this still won't compile, because you're trying to set a reference to a thing with the value of a pointer to a pointer to a thing ... that's nonsense, they're completely different types.

SHR's answer shows some correct ways to create a member variable that refers to something else, and how to initialize it correctly.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521