Posts Tagged ‘code

22
May
13

Default assignment operators and const values

It’s been so long! Update: I’ve been working primarily in C++ for the past four months or so. Hooray! I have so many drafts. I’ve really got to just start posting stuff even when it’s not (gasp) perfectly complete. Today, we’ve got another thing that I didn’t actually learn today, and it’s pretty basic, but I encountered a surprisingly bad suggestion from Microsoft’s documentation, and it seemed worth commenting on. You C++ gurus can probably skip this one.

You may recall, lo these many months ago, I posted about warnings-as-errors and why you should enable it. Well, I’m in the position of taking a large existing project and trying to turn that functionality on, and let me tell you, even with a lot of the work done for me — I was not the first, or even the second, engineer to tackle this — it’s no picnic. Reminder: turn on warnings-as-errors from the start of your project.

Anyway, one of the issues that has come up is the following:

c4512: The compiler cannot generate an assignment operator for the given class. No assignment operator was created.

For those of you not in the know, the C++ compiler generates a default copy constructor and assignment operator for you, unless you’ve specified them yourself. This warning simply means that, for some reason, the default assignment operator cannot be generated. Note that if some part of the code were actually attempting to use this operator, the compiler would throw an error, rather than a warning. Microsoft’s documentation on the warning helpfully points out that if you have any const members in your class, you will get this warning because a const member is not modifiable and thus assignment to it will not work. It continues to add that your options for dealing with the warning are the following:

  • Explicitly define an assignment operator for the class.

  • Remove const or the reference operator from the data item in the class.

  • Use the #pragma warning statement to suppress the warning.

The engineer who looked at this before me went for both the first and the second option. The second option is the wrong option, and frankly, Microsoft should be ashamed for even suggesting it. And while the third option is appropriate for some warnings, in this case, completely ignoring the error is almost certainly never the right answer. Even the first option isn’t quite on target, or at least ignores a possible solution.

I haven’t talked about const much in this blog, but I’m a huge fan. If a member variable is declared const, any programmer using that API can assume that once the data is set in the constructor, it will not change. Removing const-ness should not be done lightly, especially when (as in this case) the member is public. Removing this type modifier opens up that member to modification by any other code. Scott Meyers would tell you to “use const whenever possible” because it is such a strong contract, and I’m inclined to agree with him.

As I mentioned before, if any code were actually attempting to use the assignment operator, you would get an actual error — the code could not be generated, so anything attempting to use that code would not compile. So we don’t need an assignment operator. We just need for the compiler not to generate one. The fix for this is easy — declare it private in the header file and don’t define it. You can do this yourself (there are a million examples on the internet), or you can just make your class inherit from boost::noncopyable, which will also declare the copy constructor private, if you happen to be using the Boost libraries already.

This is a really great practice even if you’re not getting this warning. (I believe it’s one of the first item’s in Effective C++.) If you don’t expect your class to be copied, go ahead and declare the copy constructor and the assignment operator private.

14
Nov
12

C++ Basics: Static

I’ve been working on this long, boring post about the differences in equality comparison in Perl and Python and the fundamental differences of the two languages, but you know what? I’m sick of Perl and Python! And that post was boring! So let’s talk about C++ instead.

I’m in the unenviable position of not having touched a compiler (for work) in about a year. How do you live, Maitland?, you ask, Without C++, what gives your life meaning? Those are really wonderful questions for another blog, but the fact is, while I’ve learned tons in the last year about Perl and automation (and debugging and debugging and debugging), my C++ knowledge has been getting fuzzier and fuzzier. It’s extremely unnerving. Just yesterday, I opened up one of my favorite books and I freaked out because I saw my second favorite* C++ keyword, static, and, frankly, I wasn’t sure I could remember all of its usage. Thank god I have a blog so I can write it all down.

The static keyword can be the slightest bit tricky because it has several applications, and different implications in different situations. Some people will tell you that it behaves differently or that it means something different in these different situations, but I feel like this point of view overcomplicates the issue. From my point of view, static really just means one thing: it means that for the duration of the program, there will be only one of the described object or function. Once the thing is defined, it’s defined for the lifetime of the program. In fact, static objects don’t even allocate memory from the stack or the heap — they have their own separate memory segment, creatively called static memory.

Static Objects. Static non-member objects are probably the simplest usage of static. They look like this:

static int myInt = 42;

Once this variable is initialized, it’s there for the lifetime of the program. So if, for example, you put this variable in a header file, you can change that object in your functions or class members, and the change will persist. The example above uses an integer, but the concept is the same for user-defined types as well. Static objects are scoped in the same way that any other object is. If the object is declared in a header, it is scoped by the translation unit (i.e., the source and headers required to compile a given source file) that includes it. If it’s declared inside a method or function, like any local variable, it cannot be referenced outside of that method or function.

Static Members. A static member is much like a static object except for the fact that it belongs to a class. A static member is shared by all instances of a class. The biggest implication of this is that you can modify the member completely independently from an instance of the class. For example,

class MyClass
{
public:
  static int m_myInt;
}

MyClass::m_myInt = 0;

is totally valid code! Furthermore, any instances of MyClass can modify that member, and that change will persist until some other instance (or external code) modifies that member. Obviously, making a static non-const member public is fairly dangerous (as is making any member variable public), because you have no way of controlling who can modify it, but a non-public member can be very useful when you want to keep a reference count of something, for example. And when you combine static and const, you have a great way to store immutable data that may want to be scoped and defined at compile time.

One thing worth pointing out about static members is that, unless they are const and integral, you cannot initialize them within the class declaration. Logically, this makes sense, when you consider that you could construct the class multiple times, and, if the static member were initialized within the declaration, it would theoretically be re-initialized every time the class was instantiated. Because a static member is defined for all instances of a class, re-defining it in every instance would violate C++’s one definition rule. (C++ does make an exception for static const integral members, but if I’m being honest, I don’t entirely understand the rationale except “it makes life easier,” which, in fairness, is a good thing.)

Static Methods. Static methods (not to be confused with static functions!) have a lot in common with static members. Like static members, they can be referenced without an instance of the class. The natural implication of this is that static methods cannot reference any non-static members of the class. Because they don’t require state, static methods are especially good when you have software that uses callbacks. They allow you to group functionality with your class even when that functionality does not operate on the class’s state directly.

Static LinkageOkay, here’s where it gets a little tricky. Remember how I said that static really only means one thing? I kinda lied.

So, a long time ago, in a galaxy far, far away, there was a little programming language called C. And it defined static as a keyword, and it was slightly really a lot different from how C++ defines it. If you define (not declare) a method or function as static, the compiler, knowing that it has to be backwards compatible with C, treats this as static linkage. This means that your function or method cannot be referenced outside of the file it’s defined in. I’m sure there are good reasons to do this — certainly, it allows you to write helper functions that you don’t intend to be used outside of a certain file — but I can’t say I’ve ever used it myself.

I feel like I must be forgetting something, but I suppose that’s to be expected, given how rusty I am. Hell, I haven’t even talked about extern or referenced Meyer’s excellent point about how the intialization order of non-local static objects is totally undefined, meaning you should probably avoid that and use a local static variable inside a function instead. But this is getting lengthy, so I think I’ll close it off here. Next time, memory segments?

* My favorite being, of course, const.

20
Sep
12

The Safe Dereference Operator

Once again, I have gone months without writing, and I’m sure all two of my faithful readers are quite disappointed. Personally, I’m just shocked that summer is over already. If I’m being truthful, I thought about writing several times, but I could never come up with something that I learned that wasn’t so specific to my work that it was nearly irrelevant to anything else. (Though, as I write that, I think that I should put together a post about debugging. I do a lot of that, and there are a lot of things to learn there.) Today, however, I am inspired. I ran across this little gem while reviewing a coworker’s code:

foo?.getBar()?.getAttribute("baz")

At first I thought that the file might have been corrupted by the code review tool that we use. But just as I was about to open my mouth, I realized what was going on here. I have discovered a new operator, called the “safe dereference” operator, as it turns out, and I am in love.

If that syntax looks foreign to you, you’re in good company, or at least mine. Basically, that ?. checks if the preceding value is null, and, if it is, returns nullinstead of attempting dereference and throwing a NullPointerException. Because it returns null, you can chain these suckers and just check the final result for null before moving on with your code. Pretty neat, huh? I only see two possible, minor disadvantages. First, there’s no early out. If you have eighteen safe derefs chained, your statement will check for null eighteen times. If you have seventeen safe derefs followed by a regular deref, you may still get a NullPointerException. Second, it could potentially facilitate some really nasty code. Would you want to try to figure out which of those seventeen derefs returned null? Neither would I? That said, there are plenty of situations where you might not have to.

However, before you run off screaming, “I’m going to do this all the time now!” I do have some bad news. Shockingly, this amazingly useful operator isn’t present in every single language in the world. So far, I’ve only seen it in Groovy (a scripting language that compiles to JVM bytecode), and my coworker had previously used it in CoffeeScript (a language that compiles to JavaScript). So that’s very disappointing, but this feature is so useful, I have no doubt we’ll start seeing it pop up all over the place.

For more information, check out the Groovy documentation.

18
May
12

Five things to like about Perl

It’s been a while since I blogged, huh? Look, I never said I was reliable.

If you’re like me, you thought programming was for nerds until the year 2000, when you were surrounded by a bunch of nerds you liked, and then you gave in and admitted you were not-so-secretly a nerd all along and discovered you actually like programming. If that’s the case, you were probably raised to believe that Perl is evil. I certainly was. I heard all of the lousy things about how it’s totally unreadable, and how the variable scoping is weird and kind of leaky if you’re not careful, and how the subroutines are completely not self-documenting, and how it’s totally unreadable. Then I took a job that required me to learn Perl, and while I still don’t love it, I’m making an attempt to embrace new things and not become one of those people who is totally set in her ways and completely resistant to change of any kind. That’s a good thing, right? So, to that end, I give to you a list of things to appreciate about Perl. Read it before you go hatin’:

  1. Regular expressions support. Okay, this is the easy one. If you need to parse a string (or, say, a log file), Perl will make it real easy for you. If you don’t know what regular expressions are, dude, you are missing out. Start with the Wikipedia page (as always) and then check out this awesome cheat sheet. I could do an entire post on regular expressions (and I probably should!), so I won’t go into great detail, but basically, regular expressions provide a language for matching, grouping, and manipulating strings (or substrings) that allows you to operate on said strings in a concise and readable way. That’s right, I just said regular expressions and, by association, Perl were readable. Bring it on (in the comments), haters.
  2. String formatting. It’s a simple pleasure, but, boy howdy do I love the fact that I can reference a variable in a string in Perl. No concatenation, just embedded right in there. Love it.
  3. Compile-time failure. Obviously, this is a feature of all compiled languages, but Perl isn’t a compiled language! As a result, you get (some of) the benefits of a compiled language along with the development and iteration speed of an interpreted language. Pretty nifty, huh?
  4. Brevity. One of the reasons Perl is often unreadable is because you can do a lot in a one-liner. This can be incredibly frustrating, but it can also be incredibly awesome, especially if you do something crazy like add a comment.
  5. 37 ways to do anything. Another reason why people complain about the readability of Perl is the lack of consistency. This is because Perl provides eleventy billion ways to do anything. It’s a blessing and a curse, in that consistency is a good thing, and a hammer isn’t the right tool for every situation. So, it’s nice when you can come up with a screwdriver, even if that screwdriver doesn’t fit into your previously established pattern of hammers.

In all fairness, I still like Python better. I find that it has better support for object-oriented programming, a better (read:existing) type system, and is generally more human-parsable. In fact, I started this post with an attempt to come up with 10 things and gave up after 5. That said, as I learn Perl, perhaps I’ll grow to love it more. Perhaps.

01
Aug
11

Inlining and #includes

I’m on build coverage tonight, meaning I’m working until 2AM. Not the most glamorous aspect of the game dev industry, but when you’re trying to hit beta, making sure we have solid builds for QA every day is pretty important. So at least I’m important. Right?

So, the incremental build failed on me in an interesting way this evening. A header failed to compile because there was a class method defined (inlined) in it that used a function that wasn’t declared in any of the included headers. This, in and of itself, isn’t a particularly interesting failure. In fact, it’s a fairly typical, easy-to-catch-on-your-own-machine failure, one that you can usually shoot your fellow devs with nerf darts for causing. What made this particular instance interesting is that the check-in that broke the build wasn’t the one that broke the code.

Of course, it’s fairly common for a perfectly valid piece of code to expose a flaw in another piece of code, but I just couldn’t seem to figure out how the original code, which clearly called a function that wasn’t declared in any of its included headers, had ever compiled. My first thought was that maybe before this check-in, the header had included another header that had included the necessary header, but when I checked, none of the included headers had changed. It turns out the issue was that the new code changed the method from private to public.

Previously, the method had been private, meaning that it was guaranteed not to be used by any other translation units, so, even though the header was included by other files, that particular method was expanded. In the source file for the defined class, the header include was preceded by an include for another header which did declare the needed function. Once the method was made public, that method became expandable in other translation units, ones that may not have had the missing header in their includes.

This fix for this particular issue is incredibly simple — add the necessary header to the includes. But what’s the moral here?

  1. Always include all of the necessary headers for your code, and don’t rely on compilation to tell you whether you’ve done so. If you’re worried about build times or violating the one definition rule, use include guards. Actually, always use include guards. It’s a tiny amount of effort and extremely low-risk for a potentially epic payoff. (If you name your guards after the namespace and class that they guard, your chance of naming collisions is slim.)
  2. Please, for the love of all that is good, compile your code before you check it in.
30
Jul
11

ThreadHead

Some people don’t like threads, and with good reason. They complicate a program and introduce a whole new class of potential bugs that you don’t see in unthreaded software. However, while I’m the first to espouse the KISS principle, I think there are certain situations (like trying to render 60 fps on an Xbox 360), where the benefits outweigh the dangers.

That said, I always feel really embarrassed when I introduce a deadlock into the codebase, especially an easily avoidable one, like I did a few days ago. Once they’re in, deadlocks are devious little bastards and managing to reproduce them with a debugger attached is a royal pain. Assuming you’re lucky enough to discover that they exist before your game ships. That’s why you have to catch them before they make it into your code repository. So how do we avoid this terrible scourge? With this one simple rule:

Always grab mutexes in the same order.

It really is that simple. If you know exactly what mutexes are being acquired, in what order, by every part of your code, you’ll be absolutely fine! Of course, this is akin to someone telling me to eat right and exercise. Sure, it’s simple and effective, but with that kind of effort involved, I’m more likely to go for the tube of cookie dough and some miracle drug featured in 3AM infomercials. But, just as every dieter has their own tips and tricks for avoiding brownies and hitting the treadmill, I have a small but growing collection of guidelines for writing thread-safe code.

  1. Minimize the scope of your mutex grab. This one is easy. The greater the number of lines of code executed while you’ve acquired a mutex, the greater the chance that one of them acquires a different mutex. The more mutexes acquired, the greater the chance of deadlock. So restrict the scope of your mutex to what it is supposed to protect. No more, no less. If you haven’t yet subscribed to the Resource Acquisition Is Initialization philosophy, now would be a good time to start, and apply it to your mutexes.
  2. Know what your mutex meant to protect. This goes hand-in-hand with the previous guideline. If you don’t know what you’re trying to keep consistent, you can’t know what the scope of your mutex should be.
  3. (Try to) know the order of mutex acquisition in the codepath you’re modifying. This one is a bit trickier. The advice I’ve always heard is to designate a mutex order from the start and always abide by it, but in practice, I’ve yet to see that happen, and honestly, I can’t think of a good way to document and communicate that to new coders, especially with a changing codebase. Instead, you usually have to determine the order by reading the code. Going down the chain is pretty straightforward (if sometimes a bit tedious), but determining  all of the clients of your code and what order they grab mutexes can be nearly impossible, especially if you’re working in a large codebase or your mutex is embedded in low-level code (like, say, new or alloc). Theoretically, it seems like it would be pretty easy to make a tool that crawls your code (like test coverage tools do) and writes out an ordering, though I’ve never done it.
That’s all I’ve got. It’s not perfect — even if you do know the order of mutex acquisition in your codepath, it still might be different in another codepath. But I think these guidelines make some of these nasty bugs a bit more avoidable. The bug I fixed today, for example, could probably have been avoided if I had not assumed that the code it called didn’t acquire any mutexes. If I’d noticed that, I might have then gone on to see where else that mutex gets acquired, and noticed that I was introducing an out-of-order mutex grab. Or maybe not. But at the very least, I’d have been aware of the order for the next time I modified the code, something that has saved me some pain multiple times already.
26
Jul
11

Yes (/WX)

About a month ago, I realized that I was learning a lot and not writing it down. So I decided to start writing it down. A month later, I don’t remember what I learned that was so important, but I figured I should just start writing. Some of it will be technical. Some of it will be common sense. Most of it, you’ll probably have heard before somewhere. I’ll start with something that I tend to re-learn every project.

Treat warnings as errors: Yes (/WX)

I know some of you are saying, “But I plan to use that unused variable later!” or “Hey, I *know* that variable gets initialized in one of the branches of my if case, so it’s okay.” To put it bluntly, you’re wrong.

If you’re not using the variable now, replace it with a TODO comment, which has at least some chance of reminding you that you were supposed to do something with it. (No, it’s not a good reminder, but trust me, one more warning in the inevitable sea of warnings will not be any better.) And as for that variable that you know is going to be initialized in one of those branches, when was the last time you touched a piece of code and it never changed ever? That never happened? That’s what I thought.

But why should you care that your cup overfloweth with warnings every time you build your solution? Well, for one thing, they’re warnings, not beer. They’re an indication that something is behaving not quite as intended. It may mean a little bit of code bloat, which is not such a big deal. Or it could mean that you wrote this code when you were really tired, and you didn’t actually use the variable you thought you were using. But if it’s only a warning, amid a sea of warnings, you’re not going to notice until your code doesn’t do what you thought it should do, and it’s the middle of crunch and you’ve just forced QA to fail the build that was supposed to go to cert.

Or, more importantly, you might find that some other project that you didn’t build locally does treat warnings as errors and then your change fails on the incremental build, and everyone will point at you and laugh.




About

My name is Maitland Lederer, and I’m a video game developer. I learn stuff you probably already knew and have opinions you've probably already heard. I figured it might be a good idea for me to start writing down the stuff I've learned so I don't have to relearn it. It's not, like, great wisdom or anything. It's just things I happened to learn, usually today.

Header photo by D Sharon Pruitt, used under a Creative Commons License.