|
Some more links: The C++ Standards Committee The C++ Source Overview of Generic Programming Exception Safety
|
# ¿ Feb 16, 2008 01:48 |
|
|
# ¿ May 3, 2024 21:19 |
|
mracer posted:Ok, more of a Visual Studio question. Whats the best way to step thru code with many macros. you know #define functions. For things like what you just posted you shouldn't really be using macros, just use inline functions, unless you want the code strictly C89. I don't know offhand if there is some kind of trick in Visual Studio to let you step through macros, but one portable trick that will work in all IDEs is to instead implement your macro as a #include (though you usually only want to do this with very long macros, especially if there is further preprocessor iteration during invocation). For instance: code:
Remulak posted:What's bugging me now is package handling - ideally I need to deal with a zip file with some pictures, binary resources, text, and metadata. My first thought was OpenXML, specifically Open Packaging Convention, which is MADE for this and has a nice API. My second thought was *oh gently caress*, this won't work on the Mac. While it's submitted for standardization it doesn't look like there's a Mac or specific cross-platform C++ approach.
|
# ¿ Feb 17, 2008 03:50 |
|
Lexical Unit posted:Also, in trying to get code like that shown above to compile I was meet with this error from gcc 4.0.0: From the error it looks like you probably either did not define my_container::const_reference or you defined it incorrectly [Edit: Actually, it sounds only like the latter, not the former, since otherwise you'd get an error during instantiation of insert_iterator, not during the call]. When you are implementing custom containers and iterators and want to use them with standard library algorithms, just always make them compliant and you'll avoid issues like this. It's not much more effort than just adding proper typedefs/traits. That Turkey Story fucked around with this message at 00:39 on Feb 18, 2008 |
# ¿ Feb 18, 2008 00:30 |
|
Lexical Unit posted:Hrm, that may be the case but then is this not correct?
|
# ¿ Feb 18, 2008 05:45 |
|
Lexical Unit posted:Thanks, that certainly clears up that mess. Not sure how you deciphered the exact problem from that error though, here's what my thought process was, line by line: You read it almost fully and were just about there but then you stopped! You already narrowed it down to pretty much being that the only thing your code was providing at compile-time here which was even showing up in the message was const_reference (sometimes it's a little bit harder than this and what you did wrong won't be mentioned explicitly). The main thing that tells you that it definitely was const_reference being improperly defined was: code:
From the top, you know it's an error directly in the merge algorithm. It's extremely unlikely that your library's standard merge algorithm is implemented incorrectly and you are using a good compiler, so it's probably not some weird compliance problem. Assume it's how you're using it. The compiler tells you what types you used for iterators, which were just int*, so you can safely rule out that being the problem since pointers are valid iterators right out of the box, at least concerning compile-time type requirements (and since this is a compile-time error, that's all that would matter here). The only other option is it's something wrong with your last type, std::insert_iterator<my_container>. Again, since insert_iterator is standard, it's very unlikely it's a problem in insert_iterator itself, so you probably are using it with a type that doesn't properly meet its requirements. So then you get to: code:
code:
code:
Even if you didn't realize that immediately, still without following the link to the line in code, it looks fairly clear that *__first2 is probably an iterator being dereferenced and you passed in int* objects for iterators, so the statement is very likely to be similar type-wise to: code:
Apart from that, you should usually try to be conscious of rationale when writing code. Having a nested const_reference type be a reference to the type it is a member of probably isn't too useful so that should maybe set off some bells when you are writing it. If you don't understand the design rationale behind the code you are using, you should try to learn it both so that you may use the code the way it was intended and so that you can use similar rationale in your own designs, especially if it is an extension of what is already written. Really though, when making your container standards compliant you should have a good book or the standard at hand to tell you the requirements to begin with which would have helped you avoid this problem form the start (although, as a side note, requirements will all be explicit in code with C++0x which will pretty much even remove the need for any resource at all when making your types meet proper requirements, since type requirements along with axioms are a part of the code itself... with the exception of complexity requirements...). Lexical Unit posted:And when you say "get used to reading the error messages" do you mean simply from continued experience, or is there a better way you can suggest?
|
# ¿ Feb 18, 2008 22:51 |
|
Avenging Dentist posted:Well yes, that's the point. The example is greatly simplified; the original involved a complicated chain of template instantiations and was non-obvious, especially since it broke in a completely separate area (the typedef'd template was instantiated with base::foo and all subsequent references to that template, typedef'd or not, used that instantiation). Are you saying that the base class was dependent on a template argument of the child? If so, on a compliant compiler you should have gotten an error at the typedef which would have probably saved you some trouble (since foo there isn't a dependent name you'd get error in the first phase before you even instantiate the template, but vc++ won't catch this because it incorrectly pushes everything off to instantiation). It always helps to use gcc instead of vc++ when doing template stuff.
|
# ¿ Feb 28, 2008 16:20 |
|
Lexical Unit posted:Contrived example ahoy! That's entirely a different issue -- your problem there is that you're misusing the size type for something other than its actual purpose. The size type is the unsigned counter-part of the container's iterator difference type and is used for things like the number of elements in the container, unrelated to that "weird_thing" size_type in your example. As for your original question, again, just use the unsigned counterpart of your iterator difference type. Usually these are std::ptrdiff_t and std::size_t respectively, but they might be different depending on your container's needs.
|
# ¿ Mar 5, 2008 02:10 |
|
illamint posted:I see that there's Boost.Regex, but we have to hand in our source code at the end of the project and I'm not sure that it's feasible to merge the Boost shared library stuff into my makefiles just for this. Should I just parse it by hand? Is there a better solution? I'm used to being able to just go to the Java or Python docs and glance at the syntax in the manual but I'm having kindof a hard time doing that with C++. There's also regex in TR1 that's based off of Boost.Regex and is probably supported by your compiler's standard library already.
|
# ¿ Mar 6, 2008 22:11 |
|
very posted:Why is my "this" pointer changing on every line of execution? Your this pointer should never change. If you are in a member function and the this pointer is one value, then later on in the same function, this is a different value, then you are either writing past the end of a buffer that you allocated on the stack or you are writing to a memory location on the stack via a dangling pointer to something that used to be on the stack but has now left scope. If there is no code that could be writing values as you step through your code, but this is still changing between lines, then you may have passed a pointer to a stack-allocated variable to another thread (i.e. via a call to some library you are using) and the value is being changed from that thread even though your local object had since left scope, meaning it is writing to whatever happens to be in that memory location now, which in this case is possibly your this pointer. FatCow posted:I'm using a stl set to hold multiple instances of a class. Is it considered poor form to make things 'mutable' that aren't used in the comparison operator to get around the implicit cast to const? It's kind of hackish, have you considered using a map instead or are you unable to partition the type? If you have Boost you might also want to consider using a Multi-Index Container and modify the value with its "modify" function template.
|
# ¿ Mar 13, 2008 04:04 |
|
Yes.
|
# ¿ Mar 19, 2008 07:31 |
|
CasualCliffy posted:I'm trying to do the following: If you really want this, put the implementation of your class into a private base, then, from inside Foo, pass off that base to T so that it may access the implementation.
|
# ¿ Mar 25, 2008 17:11 |
|
Plastic Jesus posted:Yes, Rob Pike is an idiot. I don't care who said it, good programming is not authoritative and that is some of the worst advice I've ever heard. It could come from the mouths of K&R and it'd still be garbage. In fact, it is so terrible that when I first read the quote I assumed it had to be a joke! Plastic Jesus posted:What I generally do now is have a monolithic include file to distribute with my libraries, but within each project I adhere to Pike's Law. One distinct advantage that's come of this is is a better understanding of which components use which other components, making bad design is much more blatant. Note also that 95% of my code is c, not c++, so it's easier to get away with this approach. You don't think that adhering to this "law" is a bad design on it's own!? You don't force users to manually include all dependencies for lots of reasons, even apart from the obvious tediousness and room for error. Forcing other programmers to include the dependencies also means that the user has to worry about changing all of the files that include your header if dependencies are added or removed, not to mention the fact that you are requiring the user to know details that are specific to an implementation when in actuality they can be made entirely transparent. I can only imagine what would happen if you were working on a cross-platform project where different system headers had to be included depending on the operating system -- now all of a sudden the user of the header file has to do a preprocessor check for what OS they are targeting to figure out what additional header files they need to include. Dependencies should be automatically included, especially when they potentially vary depending on implementation. Plastic Jesus posted:The real question is, how pissed off is the next developer to take over my projects going to be? Very, I assume. Most likely they would hunt you down and kill you. At least that's what I would probably do.
|
# ¿ Mar 27, 2008 17:15 |
|
The Red Baron posted:I'm wondering if it's at all possible to further specialize a nested class of a base class in its subclass(es)? Not in standard C++, however the VC++ compilers have a little hacky way to make it work which is actually what is used to provide VC++ with native support for Boost.Typeof.
|
# ¿ Apr 14, 2008 20:32 |
|
Scaevolus posted:This is a dumb question, but were most of these vectors representing triples? (<x,y,z>) Oh my lord... I hope that isn't what he was using std::vector for!
|
# ¿ Apr 24, 2008 22:44 |
|
vanjalolz posted:Ha Ha what the hell? Do Boost pointers actually add anything useful to warrant such terrible syntax? They're not different pointer types, it's just a metafunction that yields a regular pointer. Avenging Dentist posted:Quick question, which hopefully That Turkey Story can answer: is there a library to support properties in C++ (a la C#)? If not, I'm going to write one... I though I had this discussion with you but maybe not. I actually made a library for properties in C++ a couple years ago but it's impossible to make one without overhead except in certain cases unless you complicate your encapsulating class definition (and in the case of empty types, you're out of luck). The reason is that if you want the standard . syntax, you generally have to make a dummy object that needs access to the encapsulating class, which you can't directly do without storing redundant information. A quick example of a common situation that causes problems is a container with begin, end, and size properties. To get around having to have the internal property object need access to the encapsulating object to pull out iterator data, you can just store the begin iterator inside of the begin property and store the end iterator inside of the end property, but then what do you do for size? Often size isn't explicitly store in containers at all and is instead just calculated on demand, such as internally doing end() - begin() when you call size() for std::vector (which is very common). The issue is, how does your size property dummy object get access to the begin and end iterators? It can't directly access them because they are contained in some object other than itself that it does not directly or indirectly encapsulate. Since you are going to be using overloaded operator = and an overloaded conversion operator for access and because . itself is not overloadable, you have no way of passing a reference to the data transparently during the access. Instead you have to do something like always store a reference to the encapsulating object from within your property, which just needlessly bloats the size of your encapsulating object and also adds some additional overhead such as for initalization. Not only that, but the maker of the type now needs to explicitly initialize the property in his constructor, which makes his own code more complex. Another trivial example that causes problems is a bunch of properties that map into a bit-field. You can't stick part of the bit-field in each member, so for each of those properties, you're going to be taking some damage. Now all of a sudden you need O(N) redundant self-references stored indirectly in your object, where N is the number of bits you are accessing, with each property generally taking sizeof(void*) space a piece, and each needing to be separately initialized in the constructor. Then there is the issue of properties with virtual accessors. If you accept all of the problems mentioned above and continue on, virtual functions add even more hassles. Why? Because now the implementation of your accesses needs to be a call that is forwarded to a virtual function in your encapsulating object, since if you just directly make the functions virtual in your property dummy object, deriving from the encapsulating object won't allow you to override your property's virtual functions (and even if you could, it would still imply that each of your properties with virtual accessors has its own vtable pointer, which again would cause hell to the size and initialization of your overall object). All of these problems are pretty much show-stoppers, at least with the common C++ philosophy. If you still want to go on, what I ended up doing, just because I refused to be defeated and wanted to see something remotely similar to properties even though I'd never actually use it, is overload a binary operator for accessing the name of the property. Then, since that function has access to both the encapsulating object and whatever object you are using for a name, you can create a simple temporary during the access which holds a reference to the encapsulating data and that has overloaded operator = and conversion. I chose operator ->* since it made the most sense. So in the end, for the no overhead approach you can get access like: code:
|
# ¿ May 15, 2008 20:11 |
|
I haven't tested it thoroughly, but I just put together a little macro for simple, safe enums if anyone wants it. You need boost installed to use it (header only). I only compiled with VC++ 9 but it should be portable unless I made a poopie, which is probably pretty likely. Right now, enums must be created at namespace scope, but with some effort, that can be changed. To make a simple direction type that has north, south, east, and west constants and that default constructs to north, use: code:
code:
code:
code:
code:
code:
That Turkey Story fucked around with this message at 01:59 on Jun 6, 2008 |
# ¿ Jun 5, 2008 18:04 |
|
Paniolo posted:What's the most elegant way for a class to expose a collection? At the very least, it needs add, remove, and enumeration faculties. Preferably it shouldn't be tied to any particular container type, either. I've run up against this pattern a few times and haven't found any particularly elegant solution. Could you elaborate more on your situation? Before you decide to directly expose the container, make sure you can't just represent your functionality as higher-level operations that are internally implemented with a container. If the encapsulating class holds the container but all the manipulation is still done directly by users rather than indirectly through the class, then your type is likely just a low-level aggregate (which is okay depending on your situation, think std::pair or tuple types) or it is a container itself (which again is okay). In the case of it being an aggregate, you can always just directly expose your object rather than making a redundant interface. If it's a container itself, the easiest way to make your type a compliant container without an is-a relationship is to privately inherit from the container you are using and then promote the interface elements to public with using. From your brief description, it sounds to me like you are in more of the latter case. If you feel as though your type is neither of these things, then try to tell more details about what you are doing.
|
# ¿ Jun 8, 2008 17:00 |
|
floWenoL posted:What do you guys think of this? I just skimmed and it's not bad, but some stuff I do disagree with. I will probably make it sound worse than it is because I get really upset when people give foolish rationales, but really nothing in here is horrible. quote:All inheritance should be public. If you want to do private inheritance, you should be including an instance of the base class as a member instead. In modern C++ there are lots of reasons to prefer private inheritance rather than datamembers in certain situations, some of which are techniques that simply only work with inheritance as opposed to composition. For one, private inheritance is useful for minimizing redundancy by inheriting from a base and pulling in desired names with a using declaration rather than having to tediously create I.E. forwarding functions (which can be error prone and less efficient if not done carefully, not to mention potentially less clear). Another example is helper bases that pull in functions that can be looked up via ADL (I.E. Boost.Operators). As well, using inheritance let's you take advantage of the empty base optimization, which as a side note, is exactly how Boost compressed pair works which is on this list's approved Boost libraries -- the only approved component of Boost on the list actually (so basically the guide doesn't want you to do private inheritance, but it's okay to use it indirectly, which stinks of Java's operator + logic to me). quote:Only very rarely is multiple implementation inheritance actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be pure interface classes tagged with the Interface suffix. quote:Use 0 for integers, 0.0 for reals, NULL for pointers, and '\0' for chars. quote:Do not overload operators except in rare, special circumstances. This I disagree with entirely. First, I don't understand this talk about people expecting operations to be "cheap" (or even what the vague term of "cheap" means in the general sense). You expect the operation to do what it's supposed to do, and if there is a required complexity for a given domain at concept then it should be made known. Multiplying two matrices might be expensive, but it's still a multiplication operation. Concatenating strings with + is intuitive. Anyone who somehow thinks that using a named function called "multiply" does anything other that make you type more and make it harder for your object to be used in generic code is simply not used to a language with operator overloading and that's it. There is nothing special about operators that makes them any different from other operations other than syntax and this whole nonsensical idea of them having to be "cheap" is just silly. As well, the comment "Foo + 4 may do one thing, while &Foo + 4 does something totally different" really just blows my mind in that I can't believe somebody genuinely thinks this is a good point. Are they trying to tell me that at some point in code somebody honestly accidentally wrote &Foo + 4 instead of Foo + 4, and after doing that, it somehow bit them in the rear end rather than being caught by the compiler? Are they also missing out on the point that what they are saying would be true of integers and the built-in operator +? Maybe they are suggesting that people should use a named "Add" operation for built-in arithmetic types as well, since that goes along with their argument? Anyway, aside from that being an odd mistake to make to begin with and the fact that their "rationale" would apply to built-in operators, the expression given would likely never occur alone like that in a statement as it would be a part of a larger expression, since unless the + expression they showed has side-effects, you'd be losing any calculation being made anyway (and if the statement has no side effects, that typo would generally make no difference since there is no observable change either way, though you technically might get undefined behavior with the &Foo + 4 depending on context, but even I'll say that's a moot point and I'm a pretty pedantic language lawyer). Anyway, getting back to what this means -- this "&Foo + 4" expression will be a sub-expression of something else, for instance, you'd store the result of the plus operation in another object or pass the result to a function. C++ is a statically-typed language, so unless the rest of the expression can take a pointer as an argument or an object of whatever the result type of the + is here, you'd get a compiler error so you'd know your mistake right away! I find it extremely hard to believe that anything like what they described has or ever will occur in any competent [or incompetent] person's code. The fact is, using + makes perfect sense here for built-in arithmetic types, pointer types, and user-defined types. Barring contrived examples that don't even make sense, you have to really push to come up with sound reasons against them as opposed to being driven by blind, religious issues with operator overloading. Finally, they claim that overloading the assignment operator is bad as well along with the equality operator. I find it extremely hard to believe that using "Equals" instead of "==" is more clear or less error prone. Again, all I see it accomplishing is making it harder to have your objects work in generic code and making it seem like operators are some special devices that are only for use with built-ins. Their excuse that it makes it easier to search for in code is also very weak considering all you're doing is weeding out built-in operations, whereas if all of your user-defined types use the same name (I.E. Equals) you have the same exact "problem" (which I can't even really see as being a problem to begin with). All of their issues with operators are extremely contrived and sound like worries that people might have if they worked their whole life in another language and got an idea stuck in their head of what they personally think an operator should be as opposed to what operators really are, at least with respect to C++. quote:All parameters passed by reference must be labeled const. This is C++. You can pass objects as references, that's how the language works. Using non-const references for parameters which modify an object as opposed to a pointer is the preferred C++ way of having functions which modify arguments as it removes the issue of making it unclear about the handling of null pointers and overall it simplifies syntax. If it is unclear that an argument to a function should take a non-const reference then that is generally a poorly named function and/or the person trying to use it doesn't understand it's purpose, which either way is a programmer error. The only time I see people have issues with this are when they come from a C background where references just didn't exist so they just got used to always passing out parameters by pointer. There is a better solution in C++ so use it and stop clinging to an out-dated C-style approach. quote:If you want to overload a function, consider qualifying the name with some information about the arguments, e.g., AppendString(), AppendInt() rather than just Append(). This is just silly. Again, they all correspond to the same logical operation and having to repeat the type of your expression just to call the function is redundant, not to mention annoying. You also just once again make it harder to use the function in generic code. quote:We do not allow default function parameters. quote:You should not use the unsigned integer types such as uint32_t, unless the quantity you are representing is really a bit pattern rather than a number. In particular, do not use unsigned types to say a number will never be negative. Instead, use assertions for this. Edit: I don't know why you're getting all upset about naming and indentation, etc. You can't really fault anyone for something that's nearly entirely a subjective choice. That Turkey Story fucked around with this message at 08:30 on Jun 30, 2008 |
# ¿ Jun 30, 2008 08:27 |
|
floWenoL posted:Trap loving sprung! Let the games begin!
|
# ¿ Jun 30, 2008 17:24 |
|
Zombywuf posted:Also, exceptions, use them. I agree, but the explanation given in their decision section makes sense (their "con" list for exceptions on the other hand is terrible). The overall rationale for their decision is that a lot of the code they already have written is not exception safe and their new code needs to correctly operate with old code. I can only imagine the type of rewrite it would take to make all of the previously written C++ code at google exception safe. As for auto_ptr, I agree with you. In particular, there really isn't an alternative to auto_ptr for returning a dynamically allocated object and having the result be properly automatically managed. You simply cannot do this with scoped_ptr. When C++0x comes around this will be a different story, but at the moment, auto_ptr is the ideal standard solution. Edit: floWenoL posted:Boy howdy it sure must be nice to live in your world where performance doesn't matter! That was initially what I thought, Flowenol, but if you read their rationale, performance isn't even mentioned: quote:On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-free code. Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively difficult to adopt new code that generates exceptions. The bolded sentence at least makes me happy :p That Turkey Story fucked around with this message at 17:57 on Jun 30, 2008 |
# ¿ Jun 30, 2008 17:50 |
|
floWenoL posted:Just because it's the "preferred C++ way" doesn't mean it's the best way. Your argument as to the clarity of a function taking in a non-const reference equally applies to whether it can take in a NULL pointer argument. Aside from that, it's the "preferred" c++ way not by authority, but because it's the exact use the tool was made for and because it does everything the pointer version does for this situation but has more fitting requirements. If I personally saw code that was passing a pointer rather than the object itself, all I would have is more questions. If all you wanted to do is make it more explicit where data was being modified, which is what it seems from your argument, rather than using pointers, why not make it convention to use something like boost::ref instead, or a similar basic reference wrapper. This way you can visually see at the call-site what's an out parameter without removing the strict requirements that a reference implies. You get the explicitness that you desire without the side-effect of making it look like you want to pass a pointer to an object rather than simply the object itself as an lvalue, and you make it so that you can't legally pass a null pointer as well. Would this not be the best of both worlds? You can still easily grep -- perhaps more easily than with a pointer-pass convention. In other words, just use the convention "some_function( a, b, out( c ) );" where "out" is a function template that returns a reference wrapper. Now you are making your coders be explicit as well as abide by the limitations that references have and which pointers do not. Going off on a tangent for a second, what do you think about non-const member functions? By this I mean that calling a const member function is the same syntax as calling a non-const one (which boils down to are you passing your object by const or non-const reference once you remove the syntactic sugar). Do you see this as a similar problem to what you're describing? In other words, if you are using a non-const member function should it be explicitly noted at the call site by using a pointer to call the function instead of the object directly, such as what you do when it is a more traditional style function argument? I'd imagine you'd say that always using a pointer here would be ridiculous -- is that just because it's more expected that member functions modify the data or because there is one place to look for all member functions or is there some other reason entirely? floWenoL posted:Leaving aside the brokenness of having assignment mean 'move' instead of 'copy' sometimes (C++ overloads so many things already, why not poach an operator for this? I suggest "x << y;") Not only that, but it's extremely beneficial to have move and copy dispatched with the same syntax based on whether you are working with an rvalue or lvalue since it makes things such as the above string statements work with exactly the same written code whether a move operation is implemented or not. This is good because at a high level, a copy of a temporary here is the same logical operation as a move of a temporary since you can't access the temporary again to observe a potentially different sate. You can look at it as an implementation detail that pulls in an optimization based on type information known at compile-time. This has huge benefits. In generic code, or simply in code that was written prior to a move constructor or move assignment operation being coded, this means that the program is able to instantly take advantage of move semantics once they become available without having to go back and change anything as it was written, since it will simply be picked up by overload resolution (as it logically should be). All you have to do is recompile and your code is suddenly faster with the same meaning. For instance, in modern C++ code, once standard C++ types such as strings adopt proper move support, users of those types instantly have faster code without having to change any of their written code at all, whereas if a separate operator were used for moves instead, you'd only be able to take advantage of move constructions and move-assignment operations if you explicitly went through and changed your own code to use this new "move" operator everywhere instead (not to mention that it would be error-prone to go back and do and you would likely miss some cases). floWenoL posted:honestly once you remove exception handling that removes maybe 80% of the need for smart pointers, and in the remaining cases auto_ptr is hardly an 'ideal' solution; The idea of smart pointers is that the memory management is handled automatically so you don't have to manually keep track of ownership, and when all owners are gone, the memory is automatically deallocated. Without any exceptions at all, it's still extremely beneficial to use smart pointers since it makes it impossible to forget to deallocate your memory, especially if you are doing something like returning from a function in multiple places. No matter where you return, your memory is properly deallocated, whereas with explicit management you have to remember to deallocate at every path and you'll just get a silent memory leak if you happen to forget. This kind of memory leak goes away entirely with proper use of smart pointers. It's true that RAII helps make exception safe code, but saying that 80% of the use of RAII goes away without exceptions is a pretty big generalization, and even if it did happen to be true for many domains, the remaining 20% is still an important 20% that you shouldn't overlook. Even if it were somehow 1%, that's enough to make it important. floWenoL posted:look at all the people that have tried to write replacements for it, even Alexandrescu!
|
# ¿ Jul 1, 2008 02:39 |
|
ZorbaTHut posted:I've seen a surprising number of bugs caused by people writing reasonable, sensible equations that break in unexpected horrifying ways when the types involved are unsigned. For example: First, before going into anything at all, I'd recommend using iterators here which as a side-effect avoids the issue of sign entirely, and if for some reason you didn't do that, I'd still say say use string::size_type instead of int and just don't write an algorithm which relies on negative values. The reason is, if you write your loop correctly and your loop uses the proper size type, your code works for all strings. If, on the other hand, you use int, your loop variable will risk overflow on larger strings no matter how you write it. Your algorithm is not going to be correct, at least in the general sense, not including limits from context. In the end, I'd rather write the code properly and have it work for all cases as opposed to write it in a way that works only for some subset simply because of a fear and/or misunderstanding of working with unsigned types. I'd hope that in your example you're at the very least asserting that mystring.size() <= numeric_limits< int >::max(). Either way, your for loop example is hardly indicative of why you should never use unsigned types even if that code actually were able to handle all strings. If anything, at least just recommend defaulting to signed if you are unsure rather than disallowing unsigned types completely for arithmetic calculations, though even that I'd disagree with. Use the type that makes sense for the job. Period. Strictly disallowing unsigned types for arithmetic calculations is foolish and is going to push you to write code that is incorrect in very subtle ways. Programming can be tricky, but things like forcing people to use signed types only gives the illusion of making your code safer. floWenoL posted:You also have to take into account that using unsigned inhibits compiler optimizations and so that 'free' range boost may come at a performance cost.
|
# ¿ Jul 2, 2008 21:49 |
|
crazypenguin posted:Zorba provides a slightly contrived situation but a very good example of the kind of subtle and unintuitive bugs unsignedness can produce, and all you can do is rave about how the situation is slightly contrived? crazypenguin posted:The point is you can do perfectly normal things with signed integers because it's pretty easy to avoid +/- 2 billion (all you have to consider is whether 32 bits is big enough). You pretty much always have to start thinking about modular arithmetic with unsigned integers because it's drat hard to avoid 0. floWenoL posted:It's worth pointing out that using iterators here isn't correct either. For an empty string, begin() == end(), and so you'd be comparing one before the beginning of the array, which isn't necessarily valid (according to the standard). Not to mention the fact that if you used == instead of < (as is common with iterators) that would be an error, too. At least Avenging Dentist and falafel are sane. floWenoL posted:It's not that iterators are entirely inappropriate, it's just that sometimes using indices is clearer; recommending "always use iterators" is the C++ equivalent to the (equally fallacious) mantra of "always use pointers". floWenoL posted:If you have a vector and you know you won't have enough elements to run into size issues, using iterators is unnecessary, verbose, and in fact may introduce bugs due to the fact that you have to repeat the name of the container twice, which is exacerbated by the fact that said verbosity encourages copying-and-pasting iterator-using for loops as to avoid having to type out vector<blah blah>::const_iterator or "typename T::const_iterator" (don't forget the typename!) yet again. Entheogen posted:the reason to use signed integers for indecies of arrays is that you can set it to -1 to signify it not pointing to anything. Which sometimes you have to do. Otherwise what is the issue? both take up the same space. That Turkey Story fucked around with this message at 01:55 on Jul 4, 2008 |
# ¿ Jul 4, 2008 01:43 |
|
Quit being a jerk floWenoL. Let's all just relax and have a nice discussion about how much C++ owns and how everyone is a terrible programmer except for me, you and AD.
That Turkey Story fucked around with this message at 02:27 on Jul 4, 2008 |
# ¿ Jul 4, 2008 02:22 |
|
I find it hard to believe that using the proper datatype is over-engineering.
|
# ¿ Jul 4, 2008 03:37 |
|
I usually just run it and then count aloud to myself.
|
# ¿ Jul 13, 2008 04:08 |
|
I'm really good at counting.
|
# ¿ Jul 13, 2008 04:15 |
|
Entheogen posted:Also is there a way to get around using some confusing rear end referencing and dereferncing operators when dealing with iterators on containers that contain pointers themselves? Adapt the iterator similar to how you make reverse iterators. Boost actually has an iterator adapter for exactly your situation. Edit: Also use BOOST_FOREACH instead of that macro you posted! It's more portable and only evaluates its macro arguments once.
|
# ¿ Jul 20, 2008 22:01 |
|
Lexical Unit posted:Ok, so I'm using private inheritance and promoting the methods I want to expose in the base class with using directives (did I get those technical terms correct?) but I'm a bit confused about one thing. You can't. You need to make a wrapper function.
|
# ¿ Jul 21, 2008 18:13 |
|
litghost posted:I am sorry to say this completely wrong. C++ lets you do terrible terrible things sometimes: No, your code is what's wrong. ref_bob's initialization has undefined behavior as does trying to access ref_bob2 after bob2 was deleted. There is no way to legally work with a null reference and it is safe for your compiler to rely on that fact. Null pointers on the other hand are perfectly fine and can legally be formed.
|
# ¿ Jul 22, 2008 16:26 |
|
Vanadium posted:
code:
|
# ¿ Jul 22, 2008 22:51 |
|
Lexical Unit posted:When is it safe to use this idiom: Vectors are always guaranteed to take up contiguous space, but after you resize the sequence, any pointer you had into the sequence before becomes invalid. Edit: So in other words, yes, your second example is safe (though the first one isn't because the vector is empty).
|
# ¿ Jul 24, 2008 16:15 |
|
Lexical Unit posted:Awesome. I thought I read somewhere that using that idiom to fill a vector was bad, but it was just on some crappy blog and I never really trusted it. And being that I almost never need to use that idiom, especially for filling up a vector, I never looked into it further. Thanks for the clarification First, watch out because that code isn't exception safe! If any of those new operations in the for loop throw bad_alloc, you are leaking memory. Make sure you handle and rethrow or use RAII. A simple start is to make fruitloops a std::vector instead of a char** (or perhaps better, a smart pointer like boost::scoped_array if you have boost). Second, do you mean the API takes a char** or char const* const*? If it's just an API not using const correctly, as in it's taking const-unqualified data even though it's guaranteed to not modify the data, you can just make a std::vector or scoped_array of char const* and then const_cast when passing the data through the API.
|
# ¿ Jul 25, 2008 19:57 |
|
Lexical Unit posted:Oops! In other words (untested): code:
|
# ¿ Jul 25, 2008 20:42 |
|
Lexical Unit posted:The pointer returned by c_str() is valid to use so long as the string remains unchanged, correct? I think I'm getting the hang of this... I hardly ever need to think about this because I'm usually not interfacing with C libraries. Yeah.
|
# ¿ Jul 25, 2008 20:54 |
|
Thug Bonnet posted:Well then putting aside the initialization list it seems like just doing assignment in the constructor would be more readable? As long as you have all trivial datamembers or if you aren't that concerned with efficiency, use whichever one you find easier to read. It won't matter. prolecat posted:I have to disagree when the optimization in question is something that's already very easy to do and just as readable (in my opinion). No sense being slow when there's really no reason. If you are so concerned about optimization, all floWenoL's version needs out of a compiler is NRVO support (which most if not all modern compilers support), and in the case of a struct with non-trivial assignment, floWenoL's version will likely be more optimized whether NRVO is supported or not. Edit: In the case of all trivial datamembers, I agree, the version with assignments done in the constructor is the simplest approach and likely just as efficient. That Turkey Story fucked around with this message at 18:08 on Jul 31, 2008 |
# ¿ Jul 31, 2008 18:04 |
|
I think unordered_map is used because the name stresses its properties more-so than implementation.
|
# ¿ Aug 16, 2008 22:19 |
|
Holy poo poo you guys are retarded.
|
# ¿ Aug 17, 2008 17:36 |
|
Hammerite posted:In the file classes.h there is the following definition of a class, "button": destroybtn != destroybutton ensurebtn != ensurebutton Also, why are you using a macro for BUTTONX? Just use a constant if you need a constant.
|
# ¿ Aug 19, 2008 18:46 |
|
|
# ¿ May 3, 2024 21:19 |
|
The Red Baron posted:Until C++0x brings along template typedefs, the only thing I can think of is indirecting the whole thing through some dummy class that lets default parameters actually be used, like so: This method is what is used right now, even in the STL -- that's pretty much how allocator passing and some_allocator::rebind works (allocator instantiations basically double as their own wrapper by design). STL containers don't take template template parameters for their allocator argument even though they logically could. This was done both because template template support was not common in 1998 and because it would mean that your allocator template would require the exact same amount of arguments as was specified in the template parameter list. Both of these problems are solved by adding a level of indirection as in your example.
|
# ¿ Aug 25, 2008 20:10 |