Jump to content

  • Log In with Google      Sign In   
  • Create Account

Brother Bob

Member Since 26 Nov 2001
Online Last Active Today, 06:50 PM

#5180118 c++ smart pointer question

Posted by Brother Bob on 13 September 2014 - 04:14 PM

Thanks for the lightning quick replies everyone. That clears up a ton of questions I had and answers my initial questions perfectly. I was definitely thinking of smart pointers simply as safer replacements to raw pointers.

They are safer replacement, but when there's no risk there's no reason to go safer. What they are not, however, are arbitrary replacements. That is, don't just replace your pointers, but replace them when needed to eliminate risk of resource leakage. Now, "when needed" is about learning about ownership in general and how the different smart pointers work. That comes with experience.

 

I'm going to admit, I'm still a little fuzzy on when exactly I would need to use a pointer (of either sort). Even in my more complex games, with dozens of classes and vectors of classes interacting with each other, I seem to be able to work around them just fine. I'm mostly trying to learn more about them to figure out when exactly it would be appropriate and necessary (or even just more efficient) to use them. I'm happy enough to avoid them, but I'd prefer to avoid them knowing why I'm not using them, rather than out of ignorance (my current avoidance is more of a crutch than a purposeful use of the alternative methods).

It is perfectly fine and possible to write complex software (with some definition of complex, of course) without explicitly touching dynamic allocations. You can do dynamic arrays with vectors for example, and the vector will safely handle its ownership by itself.

 

Once you start allocating "dumb" resources, for example allocating objects with new or some other function that gives you, the programmer, the responsibility of releasing said resource, you can/should look into smart pointers. But if there's no ownership you have to manage, or on other words; you're not given the responsibility to clean it up by yourself, then there's no reason for smart pointers either.

 

Take KulSeran's post above as an example. The first code box allocates a dumb resource and you have to call delete on the pointer. That's a perfect place for a smart pointer as shown in the second code box. The third code box doesn't allocate anything dynamically, the integer has automatic storage and nothing has to be cleaned up. There's no need for a smart pointer here because, as said, there's nothing to clean up.




#5180108 c++ smart pointer question

Posted by Brother Bob on 13 September 2014 - 03:09 PM

The smart pointers are about managing the ownership of a resource. If you store an object within an std::unique_ptr, you're telling the smart pointer that it has exclusive ownership of the object and is responsible cleaning it up.

 

But the problem is that you're trying to hand it an object, an integer variable, with automatic storage to a smart pointer that is supposed to claim ownership of it. The integer variable is already exclusively owned and managed by the surrounding scope (function body, for loop, whatever scope it is defined in) and you cannot transfer that ownership to the smart pointer.

 

Smart pointers are not arbitrary replacements for naked pointers; they are tools for managing ownership of objects. If you're not allocating objects dynamically, you most likely don't need any smart pointer at all for the object because if it is not dynamic then it is probably statically allocated or has automatic storage.




#5179426 C++ Function Pointer Casting

Posted by Brother Bob on 10 September 2014 - 03:19 PM

Consider the hypothetical call to func() in your last example; what is the value of the this pointer inside A::foo() once func() is called? In other words, which object do you expect the member function to be called on?

 

The moral of the story is: you expect it work work as long as the functions have the same signature, but someFunc() and A::foo() are fundamentally different.




#5178734 Base Class Undefined

Posted by Brother Bob on 07 September 2014 - 02:10 PM

A source file that includes character.h alone, such as character.cpp, will end up in a translation units that is built like this:

  1. The file character.cpp, which is being compiled, includes character.h to the translation unit.
  2. The file character.h includes world.h.
  3. The file world.h includes character.h and player.h.
  4. The file character.h is blocked by the include guard to prevent it from being included multiple times, but the file player.h is included.
  5. The file player.h includes character.h, which is blocked again by the include guards.
  6. The stack of includes falls back to character.h from step 2, and then to character.cpp from step 1.
  7. ... and so on.

Pay attention to the order in which the files are included in the final translation unit. The class player ends up in step 4, but the character class it derives from is not included in the translation unit until step 5. Thus, the base class is actually defined after the derived class despite your attempt to include the base class before defining the derived class.

 

The solution is very simple in this case. What is the purpose of including character.h and player.h in world.h? There's nothing in world.h that depends on the contents of neither of the two files, and those unnecessary and seemingly harmless includes cause circular includes and symbols to not be defined in the correct places within a translation unit.




#5178581 Something odd about set_difference()

Posted by Brother Bob on 06 September 2014 - 02:04 PM

You can immediately conclude that using XOR is wrong because set_difference(A,B) != set_difference(B,A), but xor(A,B) == xor(B,A).

 

What XOR does is that xor(A,B) toggles the bits in A using the bits in B, or vice versa; in any case, that operation is symmetric whether you use A to toggle B or B to toggle A. The problem is that bits in A will not only reset bits in B, but also set them if they were already reset. From the set's point of view, that adds elements to the set that wasn't there to begin with. The difference can only remove elements but never add.

 

In terms of the XOR operation, you want to only reset bits that are set, but never set bits that are reset. Use the AND operator to clear out bits from the second operand that corresponds to reset bits in the first operand, and then apply the XOR on the remaining bits to ensure that only set bits can be toggled.




#5177393 Vertices with multiple UV coordinates and glDrawElements()?

Posted by Brother Bob on 01 September 2014 - 02:54 AM

Correct, and correct. Although, I don't look at it as duplicating those attributes because they happen to have the same value. They are only a part of a whole vertex, and only whole vertices can be subject to duplication.




#5177387 Vertices with multiple UV coordinates and glDrawElements()?

Posted by Brother Bob on 01 September 2014 - 02:20 AM

Short answer; no, these things have not changed since 2003.

 

The thing is, a vertex is defined as everything that defines it, not just its position. The position attribute of a vertex, and the vertex itself, are often used for the same thing. Sometimes that's correct, but in the context of OpenGL, that is not correct. The position attribute of a vertex which many faces may share all over the model is just that, the position attribute of a greater atomic entity.

 

When you say that you have two identical vertices with the same position but different color, you really have two completely different vertices. So you're not duplicating any vertices, because the two vertices are different.




#5176190 Mapping Poker-Starting Hands to 0..1325

Posted by Brother Bob on 26 August 2014 - 07:34 AM

The two two solutions above assume all possible combinations of all possible cards without regards for duplication or order. That is, you have a unique identifier allocated for {i,i} which is not a possible hand, and you get two different identifiers for {i,j} and {j,i} which in fact are the same hands.
 

Assume a deck of 6 cards for each for easy visualization; the concept extends to any size. If you just take the above solutions, you get the following matrix of enumerated hards (x- and y-axes fo the table are the cards i and j, respectively):

     0     1     2     3     4     5
     5     6     7     8     9    10
    10    11    12    13    14    15
    15    16    17    18    19    20
    20    21    22    23    24    25
    25    26    27    28    29    30

As you can see, the diagonals have a unique value for impossible hands, and the upper-right and lower-left triangular parts also have unique values for the same hands.

What you want is the following matrix:

     -     0     2     5     9    14
     -     -     1     4     8    13
     -     -     -     3     7    12
     -     -     -     -     6    11
     -     -     -     -     -    10
     -     -     -     -     -     -

where - indicates a don't care-value because those hands are either impossible or already represented in the upper-right triangle.

 

Given two card indices {i,j}, the formula 0.5*i*i + 0.5*i - j - 1 gives you those values, assuming that i and j are integers and that j<i. The formula is independent on the number of cards. It should be possible to solve this for {i,j} given a hand index. It is a single equation with two unknowns, and the quadratic equation generally have two solutions as well, but I believe there is only one solution given the constraints that i and j are integers, and that 0<=j<i<52.

 

But given the very limited number of hands, a table with pre-coded hands may be feasible. In that case, just search the table for the combination of two cards and likewise look up the table index and read which two cards it represents.




#5176022 Missile Command code review request

Posted by Brother Bob on 25 August 2014 - 11:02 AM



For example, using an array.
for(int n=0; n<6; ++n) {
static float const data[] = {100, 200, 300, 600, 700, 800};
_bases[n] = EntityC(50, 10, sf::Vector2f(data[n], 520), _baseColor);
}
Maybe not worth it for such a small piece of repetitive code, but at least it begins to separates the data from the code.


I never really considered the possibility of simply creating a data array to fill another array. Wouldn't it be expensive though to recreate the array every iteration of the loop?

 

The array is constant and has static duration. Your compiler will allocate it at compile time and there's zero additional cost at run-time other than actually accessing it from memory.




#5175828 Missile Command code review request

Posted by Brother Bob on 24 August 2014 - 09:52 AM

 

_bases[0] = EntityC(50, 10, sf::Vector2f(100, 520), _baseColor);
_bases[1] = EntityC(50, 10, sf::Vector2f(200, 520), _baseColor);
_bases[2] = EntityC(50, 10, sf::Vector2f(300, 520), _baseColor);
_bases[3] = EntityC(50, 10, sf::Vector2f(600, 520), _baseColor);
_bases[4] = EntityC(50, 10, sf::Vector2f(700, 520), _baseColor);
_bases[5] = EntityC(50, 10, sf::Vector2f(800, 520), _baseColor);
This could be a loop.

 

 
Huh, but how would I integrate the jump from 300 to 600? I can't think of a way.

For example, using an array.

for(int n=0; n<6; ++n) {
    static float const data[] = {100, 200, 300, 600, 700, 800};
    _bases[n] = EntityC(50, 10, sf::Vector2f(data[n], 520), _baseColor);
}

Maybe not worth it for such a small piece of repetitive code, but at least it begins to separates the data from the code.




#5174674 How to react on KeyPress + Release?

Posted by Brother Bob on 19 August 2014 - 04:46 AM


I had to assign the idle()-function using glutIdleFunc() not glutIdleCallback() (this one wasn't even suggested by VS).

 

My mistake, glutIdleFunc is of course correct.




#5174665 How to react on KeyPress + Release?

Posted by Brother Bob on 19 August 2014 - 04:17 AM

 

Is the display routine invoked regularly at all? Set a breakpoint into the display() routine and look what happens.

 
Yes it is, otherwise it would not draw anything I guess.

 

There's between being called once and being called regularly. GLUT will only issue a call to the display function when the contents is invalidated which typically happens when for example, the window is created, the window is resized, or when the window is moved behind other windows. Otherwise, the display callback is not called again unless you explicitly force a redisplay.

 

So, your display function is called once which explains why something is rendered, but not regularly which explains why nothing more is happening after that. You need to use the idle callback to keep the program busy all the time instead of idling when there's nothing new to display.

 

Quick solution:

void idle()
{
    glutPostRedisplay();
}
 
int main()
{
    ...
    glutIdleCallback(idle);
    glutMainLoop();
}
As soon as there's nothing else for GLUT to do, it calls the idle callback which then forces GLUT to redraw the window.
 
 

But while stepping through the method something strange happened. When the debugger hit the memcpy() line it VS opened a OpenFileDialog and said that it was missing a memcpy.asm file.
 
What does that mean it didn't throw any errors when compiling without breakpoints.

You're stepping into the memcpy call but the debugger can't find the source for the memcpy function. Could be that the source directories are not set up properly or you haven't installed the runtime library source. Quick solution is to step over the call, and into it.




#5172044 Safely eating potatoeses

Posted by Brother Bob on 07 August 2014 - 08:10 AM

#1 What does it actually mean when it says 7.22 (i'll just take it as 7) decimal digits ?

A single-precision float with 24 effective bits (23 explicit and 1 implicit bit) has log10 224 = 24 log10 2 = 7.22, which is approximately 7, digits of precision. Note that it is not 7 decimal digits after the decimal point, but significant digits; the precision is relative, not absolute.
 

#2 What is the absollutely safe range (maximum and minimum) in floats without losing information(end ressult the number will be represented exactly). And how to safely use it?

Depends entirely on what scale you work with and type of operations you do.

 

If you limit yourself to integers, you can work with integers between -223 and +223 safely. If you introduce fractional powers of two, you need to ensure that the fractions don't scale beyond your 24 bits of precision.

 

For arbitrary values and operations, there's no such thing as "no loss of information" in floating point values.




#5170661 Understanding Qt At a Deeper Level

Posted by Brother Bob on 31 July 2014 - 12:17 PM

I started diving into Qt again last night, and a few things made me wonder how it works. For example: when the UI is designed in the Designer View, is the .ui file (an XML schema) compiled into a header/source file that contains all of the controls as if instantiated in-code?

That is correct. The uic program translates your UI-file into a header file (header only though, no source file) that you include in your code to instantiate the UI. If you have a UI called mywindow you typically have the mywindow.h and mywindow.cpp files, and you'll get a file ui_mywindow.h from the UI compiler that you include to instantiate the UI in mywindow.cpp.

 

The reason I ask is because the .ui file's corresponding header/source pair's class is also prototyped in the scope of the UI namespace. Then, a data member is created from that, called "ui" within the class itself. That ui data member appears to contain a pointer for each QWidget added in the Designer. For example, if I drag a QPushButton into the Designer, and name it as pushButton in its Properties Inspector, the ui member will have a ui->pushButton member pointer within it of type QPushButton. Funny thing is, I couldn't find where the "pushButton" member was declared in-code. This leads me to think that Qt Creator's Intellisense is smart enough to parse the XML file, and a class being changed behind the scenes, or at least at compile time.

When you create a project in QtCreator, you are asked for an intermediate directory for your project. For example, if your project is located in <path>/test, this intermediate build directory is usually <path>/build-test-Desktop_Qt_5_2_1_MSVC2012_OpenGL_64bit-Debug, or a variant thereof, and depends on which version (5.2.1 in this case), which compiler (MSVC2012) and Qt build options (w/ OpenGL, 64-bit, debug library) you use. You find all temporary files from, for example, the uic and the moc compiler there. This is where you find your compiled UI header files.

 

 

Then, there are, signals and slots. It sounds like they have some sort of special definition that's triggered by the Q_WIDGET macro. Also, QWidget::connect()'s 2nd and 4th parameters are of type const char*, and it's common practice to use the SIGNAL() and SLOT() macros to pass through prototypes of functions (not methods because they don't appear to be associated with any class). I understand that that I'm calling two functions that these widgets seem to have, but how does that work under-the-hood, exactly?

I won't, or can't, go into the details about signals and slots in general, and certainly not about Qt's signals and slots in particular. See them as callbacks on steroids. When something happens, for example a button is clicked, the button's clicked() signal is emitted. This, sort of, inserts a message into Qt's "message loop", and Qt then calls all connected slots. So if you connect your onQuitButtonClicked() function to the quit button's clicked() slot, Qt will call onQuitbuttonClicked whenever the quit button's clicked signal is emitted.

 

So:

connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));

informs Qt to call this->onClicked() whenever button's clicked() signal is emitted. It does not call button->clicked() at any time, it only observes it and responds by calling this->onClicked().

 

I suggest you study the idea behind signals and slots in online resources, but basically it's a kind of callback system that let's you receive calls to functions when something happens. Sometimes the signal is passed through the message loop, and sometimes the slot can be called immediately from the signal, but those details are not really relevant to the concept of signals and slots.

 

 

Does Qt rely on some special C++ compiler, or special rules?

jwezorek already got a reply before I finished this, so I won't repeat much of it: no special C++ compiler, but it preprocesses your UI and source/header files using the UI and meta object compiler to generate additional source/header files that is passed to the C++ compiler.




#5168140 Exception question

Posted by Brother Bob on 21 July 2014 - 07:55 AM

Pointers never deallocate themselves. Use a smart pointer object to manage ownership.

try {
    std::unique_ptr<int[]> ptr(new [10]);
 
    for (int i = 0; i < 10; i++) ptr[i] = 10;
 
    throw 1;
} catch(int x)
{
}





PARTNERS