|
HB posted:The first code copies the string constant into the variable-sized array a, the second creates a pointer to the string constant before attempting to change it. These compiled-in constants are read-only by default; if you're using GCC there's a flag you can use to allow writing to them. This may just have been a slip on your part, but for new programmers it's important to note that the array a created by code:
code:
|
# ¿ Mar 15, 2008 21:56 |
|
|
# ¿ May 8, 2024 00:34 |
|
Being aware that invoking reinterpret_cast is something that should be done with extreme care in good C++ code, I was wondering if there is anything wrong with this, or if there is a better way to do this:code:
|
# ¿ May 5, 2008 22:03 |
|
JoeNotCharles posted:Since this is C++ code, why doesn't LongPacket just inherit from Packet so you can use static_cast? I considered that, but - and I guess this should have been an alternate question - I couldn't find any definitive answer on whether or not that would preserve field ordering and packing. Since it's a network packet, it needs to be bit-for-bit accurate. So, if I write: code:
|
# ¿ May 5, 2008 22:47 |
|
Vanadium posted:I do not think the language guarantees absence of padding in any case, with or without inheritance. In gcc/g++, the #pragma pack(1) directive guarantees the absence of padding in plain structs. However I'm looking but I can't find out if this also applies if you use a struct more like a class (for example, adding constructors, using inheritence, etc). I'm not terribly concerned about portability to other compilers at the moment, but this will have to build on gcc for several platforms, so I don't want to rely on something that might work on x86 but not on ARM.
|
# ¿ May 5, 2008 23:14 |
|
This may be silly/stupid, but is it in any way possible to do this?code:
The motivation behind this is that I'm writing a number of classes that all have several identical member functions that accept enumerated values, but the enumerated values are different for each class. I was thinking it would be handy to have a common templated base class that handled the implementation of these member functions so that I wouldn't have to duplicate the code. The other way to do this (my present solution) is to have each class call templated utility functions that are in an unrelated clsas, but in that case there is still an identical interface to the utility function in each class. Obviously one solution is to move the Things struct outside of the class, but then the namespace for the Thing values would have to be FooThings:: instead of Foo::Things:: which seems inelegant to me.
|
# ¿ May 6, 2008 17:23 |
|
Mikey-San posted:The strcmp() function isn't "does this match or not"; it's not a yes-or-no operation. Rather, strcmp() is a lexicographical comparison function that determines the ordering of two strings which can be identical, sorted A>B, or A<B. As a result (no pun), the return value of strcmp() is a signed integer that is equal to, greater than, or less than 0. You should perform strcmp() checks like this: You're correct, but using !strcmp(A,B) as an equality test is a fairly common idiom. It works of course because anything nonzero is true, and strcmp(A,B) evaluates to false (0) if and only if A and B are the same. It's a non-intuitive and inelegant syntax, but if you've been coding for any length of time you should be familiar with what it means, so there's nothing terribly wrong with using it unless you're trying to teach someone else.
|
# ¿ May 9, 2008 22:22 |
|
clockwork automaton posted:I'm working on creating a multi-threaded telnet server, eventually in C++, but for now I'm focusing on C just trying to get it working and ignoring threads at this point. However, I'm having issues binding to port 23. Is your program running as root? Ports below 1024 are reserved for superuser use only. Edit: By the way, the C socket functions all set errno, so you can use perror to find out in more detail what the exact error was by replacing your printf call with a call to perror (and possibly including errno.h). Smackbilly fucked around with this message at 00:06 on May 13, 2008 |
# ¿ May 13, 2008 00:02 |
|
Zaxxon posted:int *Foo In the first case, think of * as the derefernce operator. Think of int *foo as "I am declaring that there shall be an int at the location pointed to by foo", and int* foo as "I am declaring foo as type pointer-to-int." Obviously there's no actual difference between them, but that should help allay the irritation in seeing int *foo.
|
# ¿ May 15, 2008 01:31 |
|
pthreads question: Is there any disadvantage to creating lots and lots of threads over the course of a program's execution, if only a couple will exist at any given time? The context is that I'm writing an app that does asynchronous communication over UDP. Since UDP is unreliable, certain packets that are not ACK'ed after a timeout need to be re-sent. The way I'm currently handling this is: - send the packet - spawn a thread which sleeps for the timeout interval - when the thread wakes, it checks if the ACK has been received yet, if not it calls a timeout handler, which repeats this process. So every packet that might need to be re-sent gets its own timeout monitor thread. There are only going to be a few (like, 1-5) of these packets pending at any given time, but the program may run for a very long time, so there could easily be hundreds or thousands of short-lived threads created over the course of the program. Is there any problem with doing this, as long as I make sure to either detatch or join each thread? I could certainly consolidate timeout handling into one thread, but that would make the code messier and more complicated, so I'm inclined to avoid that unless there is a good reason to do it.
|
# ¿ May 24, 2008 00:42 |
|
Zombywuf posted:Why are you emulating TCP? 1. I didn't write the protocol 2. Not all packets are ACK'ed, only certain important packets 3. I'm not emulating TCP connections or flow control
|
# ¿ May 25, 2008 17:31 |
|
Insurrectum posted:When should you use cout as opposed to printf? And scanf as opposed to cin? Always and never, respectively. There's no reason to use C I/O functions in C++ when there are C++ I/O functions that do everything the C functions do. quote:When you use std::function is that just calling the function in std without having to put "using namespace std;" at the top? Yes. The :: is the scope-resolution operator. You know how when you declare a local variable in a function that variable is not accesible outside the function, so you can re-use the name in other places? Namespaces work kind of the same way, except that you can explicitly refer to a variable inside a namespace from outside that namespace by using namespace::variable. For example, cout is a variable inside the std namespace. "using namespace std;" means "import ALL of the variable names from the std namespace into the current namespace". You can of course refer to any variable in the current namespace without ::, so this allows you to write cout instead of std::cout. (Note that if you have not declared a namespace, you are working in a default unnamed namespace, which is usually fine) In some respects "using namespace" is poor style because you're polluting your current namespace with lots of variables that you may not really need. You can be more restrictive by writing "using std::cout;" and "using std::endl;", etc, to import specific variables from another namespace. If you are familiar with Java, "using namespace foo" is like "import foo.*" and "using foo::bar" is like "import foo.bar". However unlike Java, namespaces are not necessarily associated with a class (although every class is also a namespace). Smackbilly fucked around with this message at 00:44 on May 30, 2008 |
# ¿ May 30, 2008 00:37 |
|
ehnus posted:One big reason to avoid C++ I/O functions is that they add an implicit dependency on exception handling mechanisms which isn't always an acceptable option. Okay but if you're eschewing all forms of exceptions, then you're also tossing out STL and basically working in C-with-classes. I suppose some people do that, though. quote:In practice there's nothing wrong with "using namespace ...", in fact as someone who used to work in QA I greatly encourage people to use it because seeing fully qualified names littered throughout code is ugly as sin and in an individual translation unit there's no real danger regarding namespace pollution. The exception to this is in public header files -- people who import namespaces in public headers need to be shot. I wasn't advocating using fully qualified names, I was advocating the middle ground of using "using" statements that specify exactly which symbols you wish to import.
|
# ¿ May 30, 2008 03:39 |
|
SkankerX posted:It's nice to put that sort of stuff in an enum, since it's a bit cleaner looking and conceptually makes sense. That may just be my stylistic preference, though. Tbe biggest advantage is that enums are typesafe, so you will not need that extra "assert" statement to check that the parameter is in the valid range. If you have: code:
Also note that there is no problem with using an enum value to index an array - enum values are automatically promoted to integers. Note that I have assigned North = 0 to ensure that the numbers assigned to the enum values begin from zero (since I'm not sure if that's mandated by the standard or not). But you will still need a constant recording how many valid values there are for the purpose of declaring the links[] array. Unfortunately there is no way to simply query an enum type and ask it how many valid values there are.
|
# ¿ Jun 5, 2008 01:03 |
|
Vanadium posted:room->link(0, Direction(14)); Well there what you're doing is performing a type-unsafe C-style cast. If you go around doing that, all the type-safety in the world isn't going to help you, since you're basically telling the compiler "I know better than you do here; shut up". And if you actually don't know better... By the way, regarding the "counting the valid enums" problem, here's how I usually handle it: code:
Smackbilly fucked around with this message at 13:04 on Jun 5, 2008 |
# ¿ Jun 5, 2008 13:00 |
|
floWenoL posted:
Actually the real reason is because you can't declare a namespace inside a class. So if I want to do something like this: code:
Smackbilly fucked around with this message at 16:26 on Jun 6, 2008 |
# ¿ Jun 6, 2008 13:01 |
|
This is more a gcc question, but: Is there a way to force gcc to link in everything from a static library, even if you're not using it? The context is that I want to create a shared library libfoo.so which uses libbar.a, and I want EVERYTHING in libbar.a to be available to programs which link against libfoo.so without having to have libbar available. The problem is that there can be programs which use symbols in libbar.a which are not used by libfoo.so, so by default these symbols are not included in libfoo.so when it statically links against libbar.a.
|
# ¿ Jun 6, 2008 16:35 |
|
Shoes posted:What am I doing wrong? HTTP requests need to end with a blank line (because there can be multiple lines in a single request). Stick another \r\n on the end and you should be fine.
|
# ¿ Jun 10, 2008 18:09 |
|
TheBlackRoija posted:when I try to compile it a get a whole bunch of "'WORDS' undeclared (first use in this function)" errors Please post the exact error messages.
|
# ¿ Jun 12, 2008 16:19 |
|
more falafel please posted:The biggest problem people generally have with learning pointers is that they're told "oh yeah, pointers are hard, that's why I hate C," and then they believe it's some horrible convoluted thing. Agreed. Pointers are hard to avoid making mistakes with (memory leaks, etc). They aren't hard to understand. A lot of new programmers don't pick up on that distinction when some people bitch about pointer problems.
|
# ¿ Jun 13, 2008 01:09 |
|
chutwig posted:That's great, except notwithstanding that I forgot printf's return type due to my inexperience, it still doesn't explain why saying My first thought with this bug would be that the string that you're printing is not null terminated. In GDB the block that you malloc might be set to all nulls, whereas at runtime it may not be. Try using memset to set your string to all NULs right after you malloc it, and see if the problem goes away. If so, double check your sizes and string copy operations to see where you're writing one too many characters into the string.
|
# ¿ Jun 14, 2008 07:18 |
|
floWenoL posted:What do you guys think of this? The first thing is that it shouldn't be used as an all-purpose C++ coding guide. For instance, Google C++ code does not use exceptions, ever. This makes sense in the context of the performance requirements that Google's production code has, but there are plenty of instances where using exceptions is the better choice for purposes of legibility and maintainability.
|
# ¿ Jun 29, 2008 23:18 |
|
Hammerite posted:Thanks. The + operator does not concatenate C-style strings (i.e. character arrays). You need to use the strncat function. And if you're in C++ and not C, you should probably use the std::string class instead of character arrays.
|
# ¿ Jul 2, 2008 03:25 |
|
Hammerite posted:I haven't any problems at the moment, although it was hard to get the program to clear a string (so that it's blank, or appears blank) because except when initialising the string, it complains that the character array "" and the array I'm assigning it to aren't the same length. The workaround I found is to tell it the first element of the string is the terminating character, i.e. Like the last two people have said, #include <string> and use std::string, it's much easier almost all of the time. However, it is worth you while to learn how C-style strings work, since you will encounter them: A C-style string is an array of characters which is terminated by a special character called NUL. This has ASCII value 0, and is represented as '\0'. Anything after the NUL character in a C-string is ignored. This means that the 6-character array 'H' 'e' 'l' 'l' 'o' '\0' and the 10-character array 'H' 'e' 'l' 'l' 'o' '\0' 'x' 'y' 'z' '!' are both considered to be the same string "Hello". If a C-string lacks a terminating NUL, you've got problems because there's no way to find out how big an array is at run-time, so functions expecting a C-string won't know when to stop reading from the array. Consequently, if you have some string char mycstr[10], to "clear it", it is sufficient to write mycstr[0] = '\0'. Note that when you write an initializer like char mycstr[10] = "Hello", the compiler will automatically add in the trailing \0, so long as your array is large enough to hold it. Note also that this means that an array which holds a C-string must always be at least one character larger than the number of printable characters that it intends to store. The key thing to remember about C-strings is that they are really only character arrays with this agreed-upon convention that they terminate with '\0'. The language does not treat them any differently than other arrays, and consequently operators like = and + don't do special string assignment and concatenation operations like you might want them to. For example, you can't do this: code:
code:
But the thing to be careful about with all of this is making sure that you arrays have the appropriate size. Arrays in C do not automatically grow to accomodate new data. If you try to write 10 characters into a 5-character array, your program will crash if you're lucky or have other "interesting" and tough to find bugs if you're not. This means that if you do not know at compile-time how long a string is going to be (user input, for example), you need to dynamically allocate memory for the character array. And then you have to make sure you keep track of that memory and free it later to avoid a memory since C/C++ have no garbage collector. Oh, and then there's the interesting part where you will see C-strings referred to as char* (character pointers) instead of character arrays. In most cases in C, an array is interchangable with a pointer to its first element. So it's perfectly legal to have a character pointer char* foo, and say foo[5] = 'x';. This is of course assuming that you know for sure that foo is size at least 5, which you can't determine at run-time, which is why we have this whole business about '\0' characters earlier. Phew. And that's really just the half of it. In short, C strings are a huge pain in the rear end and are ridiculously error prone. Even many professional commercial programs have bugs and security holes because some programmer forgot to be careful when dealing with arrays (usually character array). You should be aware of how they work because you will encounter them, but if you are fortunate enough to be programming in C++, there's no reason to subject yourself to one of C's biggest annoyances. That's why God (Bjarne Stroustrup) invented std::string. std::string works like you would expect a string to work. = copies/assigns, + concatenates, it has a .size() method to find out how long it is, and it grows and shrinks as necessary with no need for manual memory management. It even has a .c_str() method which will convert it to a C-string if you encounter a function that doesn't accept std::string. It really is worth it to learn how that works. C++ even has other classes (e.g. std::vector) with which you can usually entirely avoid using C-style arrays in a C++ program. As you learn more about C and C++'s memory management, pointers and arrays will make more sense to you and you'll 'get' why C-style arrays and strings are the way they are, but even when you do understand it, there's no reason to subject yourself to all the inconvenience of working with them when there's a perfectly good and intuitive C++-style way to address the issue. Smackbilly fucked around with this message at 15:39 on Jul 2, 2008 |
# ¿ Jul 2, 2008 15:22 |
|
Entheogen posted:oh ok, i see what you are saying. even though macro is replaced by pre-compiler with whatever it is defined to, if data is a function call it will be evaluated 15 times. Yes, and what's worse, if that function call has any side-effects, those side-effects will be repeated 15 times. Imagine what would happen if f() were instead randomGenerator.nextNumber().
|
# ¿ Jul 7, 2008 15:04 |
|
Triple Tech posted:Question for the peanut gallery. How do you select a random integer from 0 to something higher than RAND_MAX? (Which I'm assuming is static) I'm guessing we're getting into algorithm territory... If RAND_MAX is a power of two minus one (which it usually is), you can generate two random integers, and consider them to be two halves of an integer with twice the number of bits set in RAND_MAX. This can be done with n random integers representing a number with n times the number of bits in RAND_MAX. For example, in the GNU C library where RAND_MAX is the largest representable int32_t (231-1, so 31 bits set), you generate two ints with rand(), and then OR them together to build a 62-bit integer which is equally random. (...assuming of course that you have or can create a datatype that can hold a 62-bit integer) If RAND_MAX is not 2x-1, then this isn't uniform, but there's probably a way around that if you're really interested in that corner case. Edit: It seems like you know this, but for lurkers in this thread, things that definitely do not work include... 1. Generate two numbers and add them together. Nope, the distribution will be biased in favor of numbers towards the middle of the range. In order to hit the extremes, both numbers must be either large or small simultaneously, which is less likely than other combinations. 2. Generate two numbers and multiply them together. Nope, (among other problems) the distribution will be biased towards even numbers. The result number will be even if either of the original numbers were, making the result three times more likely to be even than odd. The reason that the OR'ing method works is that if the original PRNG is any good, every bit in the original 31-bit numbers is just as random as every other bit, so if we generate 62 totally random bits, they're still totally random no matter what order we put them in, as long as we don't change them in any way (like by doing math with them). Smackbilly fucked around with this message at 18:37 on Jul 7, 2008 |
# ¿ Jul 7, 2008 18:16 |
|
bcrules82 posted:can rand() be called within a const method? anyways, i'm just returning a private variable. A const member method only guarantees that the internal state of the object will not change (and even then there are legitimate reasons that the method might internally cast away constness for some operation). It does not at all preclude stateful library calls. In your case, yes, there is no logic-related problem with calling the accessor 15 times. There might be a performance hit if you are using this macro in a loop that runs many times because your compiler may choose not to inline the accessor for some reason. However the main thing we're pointing out is that one reason to avoid macros generally is because they are prone to bugs like this where the behavior of a poorly written "function macro" is different than the behavior of an equivalent function. Ideally, you shouldn't have to care if EVEN_BITS_W is a macro or a function call, because it should work the same way. In the case of the particular EVEN_BITS_W macro that was posted, this assumption is violated because the macro version re-evaluates the argument 15 times, whereas if it were written as a function, the argument would be guaranteed to only evaluate once. This means that if you ever later decide to re-use EVEN_BITS_W with an argument that is not a simple accessor, you do have to stop and carefully think about whether the argument can handle being evaluated 15 times with no ill effects.
|
# ¿ Jul 7, 2008 20:06 |
|
UberJumper posted:3. Why should i ever use pointers? The only reason i can see them being useful, is for when creating and allocating big blocks of memory, then having that memory freed half way through the application. I've always passed everything by reference, returned references when i can etc. Consider the scenario in which a class Foo has a member that needs to refer to some other object of type Bar. Say that either you don't know what Bar object you need to refer to when you construct your Foo object, or that you want to be able to change which Bar object the Foo uses at will. Given that references cannot be uninitialized or null, and they cannot be changed to refer to something else, how do you do this with references? Answer: You can't; you use pointers. References in C++ are basically just shorthand for pointers when you only need to do very basic things with them. When you need to do more complex things like have a pointer that points nowhere, or a pointer that changes where it points to, or a pointer that points to a dynamically sized piece of memory, or a pointer that doesn't point to the beginning of an allocation, then references don't support what you want, and you have forgo the shorthand and use pointers directly. The benefit of references of course is that because they disallow those things, and those things are the kinds of things that end up causing pointer-related errors, references are less error-prone, and so you should use them when you can. But their relative safety makes them very limited, and when you start writing larger C++ applications you will encounter these limitations frequently. Smackbilly fucked around with this message at 20:26 on Jul 20, 2008 |
# ¿ Jul 20, 2008 20:23 |
|
Entheogen posted:I used pointers before to switch between two arrays that contain same types. Yes, curr is pointing to the stack. As far as whether there's a more elegant way to do that depends on what exactly you are trying to accomplish. quote:If I did something like this: This isn't legal C++ (does your compiler allow it?). int(5) is nothing more than the integer literal '5' being C-style casted to an integer, which does nothing. Literals are not lvalues (things that can appear on the left side of an = assignment) and therefore you can't legally take their address because they might not have one. quote: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? I can't seem to think of a general way to get rid of that syntax with a macro, but that's not particularly confusing to anyone who has worked with STL iterators.
|
# ¿ Jul 20, 2008 21:43 |
|
Brackhar posted:So in preparation for job searching I've been systematically solving the problems posted at this blog as practice, but I'm having a bit of trouble figuring out a decent implementation for one of the questions that would be feasible in a timed environment. Here is the question: ((1 + 2) – (3 * 4)) is a valid insertion of parenthesis. That example leaves off several valid insertions such as the one you had and, for example, ((1 + 2 - 3) * 4). However note that the question is only looking for the unique solutions that can be obtained through parenthesis insertion, not an enumeration of all possible parenthesis insertions. If you want a hint as to how you should approach this problem, I'll tell you that this problem appears to be NP-Complete (read: don't try to brute-force it!), but it is a prime candidate for a dynamic programming solution. There's nothing really C++ or C-centric about this problem - it's a test of your ability to design an algorithm. Smackbilly fucked around with this message at 21:52 on Jul 20, 2008 |
# ¿ Jul 20, 2008 21:50 |
|
Brackhar posted:So that seems the fairly obvious way to approach it, but what's the underlying mechanism to handle the evaluations? Do you parse through the string and create a tree, do you use a stack, modify the string in place...? I thought about constructing a tree, but I worried that in a timed situation I'd not be able to do the insertions in the proper order to generate all possible combinations. Iterating over every permutation is an O(n!) brute-force algorithm. It will work, but it will have an insanely long runtime for anything but the smallest inputs. I'm writing a solution to this problem because I'm bored and it's interesting, and here's the dynamic programming setup that I came up with: Parse the input set so that V(n) is the value of the nth integer, and OP(n) is the operator appearing after the nth integer. Let N be the number of integers in the equation. Now define a function Q such that: Q(n,n) = V(n) Q(n,m) = { All unique values you can get by parenthesizing terms n through m } And then your solution is the value of Q(1,N). The remaining step in designing the algorithm is how do you compute Q(n,m) for an arbitrary m in terms of V, OP, and Q? After you figure that out, you're down to the implementation details of what data structures you use to store the value sof Q, V, and OP in a program. I haven't done a full complexity analysis on this, but I'm fairly sure this ends up being pseudo-polynomial (polynomial in the size of the largest integer value that you can generate in a subterm). So it should be fast as long as the integers involved are small, even if there are a whole lot of terms.
|
# ¿ Jul 20, 2008 22:27 |
|
sarehu posted:Ultimately somebody can always throw you one of these: code:
Anyway, I'll put the solution code right in here because it's interesting/useful anyway and it's apparently not homework though it does make a really good dynamic programming exercise) This is in C++. I know you were asking about ANSI C but I really didn't want to have to rewrite your standard map and set data structures when that's not really the point of this problem code:
The algorithm, like I posted before, is this: quote:Parse the input set so that V(n) is the value of the nth integer, and OP(n) is the operator appearing after the nth integer. Let N be the number of integers in the equation. Now define a function Q such that: The missing piece is: Q(n,n+1) = { V(n) OP(n) V(n+1) } Q(n,n+k) = { x OP(y) z | n <= y < n+k, x in Q(n,y), z in Q(y+1, n+k) } Here, our subproblems are continuous runs of adjacent terms. We start with single terms, then we use those answers to build the answers to pairs of terms, then we use those answers to build the answers to four terms in a row, etc, etc. In english, the above equations for Q mean: 1. The only possible result from parenthesizing a single term is itself, so Q(n,n) = V(n). 2. The only possible result from parenthesizing a pair of terms is the operation between them performed on the two terms, so Q(n,n+1) = { V(n) OP(n) V(n+1) } 3. The possible results for parenthesizing terms n through n + k are computed as follows: For each term y between n and n + k, consider all of the possible results for parenthesizing the terms n to y and y+1 to n+k. For each pair of possible results, one from the left and one from the right, perform OP(y) on these results and add them to the set of possible results for parenthesizing n to n+k, excluding duplicates. The code above simply implements this definition of the function Q, and caches the results so that no sub-problem is computed more than once (Note that in C++, sets automatically eliminate duplicates). Then, main just parses the input string into terms and operations, and calls Q(1,N) to get the answer set.
|
# ¿ Jul 20, 2008 23:08 |
|
litghost posted:I am sorry to say this completely wrong. C++ lets you do terrible terrible things sometimes: Before you even touch ref_bob, you dereference of a null pointer, which is undefined behavior. You can't blame the language for anything that happens after you do something undefined. If your compiler happens to allow the operation to proceed and segfault on a reference later, that's fine, but that doesn't have anything to do with how references are defined to work in C++. Edit: And as far as the heap corruption trick, references are guaranteed not to be null; they're not guaranteed to always be valid (try returning a reference to something on the stack for a similar effect). Smackbilly fucked around with this message at 16:33 on Jul 22, 2008 |
# ¿ Jul 22, 2008 16:26 |
|
litghost posted:But the code compiles and runs (and dies horribly). My point was not that you should be able to do these thing, but that they are possible. You CAN have a reference to a NULL pointer, you can hold a reference to de-allocated memory. In short: Just because your code compiles and runs doesn't mean the code is valid C++. The C++ standard leaves a number of things "undefined", and if you do any of those things your code is no longer valid C++ and all bets are off. The canonical admonition is "undefined behavior can do anything, including doing nothing, crashing your program, or erasing your hard drive." If anything your complaint is that your compiler is not smart enough to detect that what you have written is not C++ and yet attempts to compile it as C++ anyway.
|
# ¿ Jul 22, 2008 16:39 |
|
Whilst farting I posted:Thanks for the explanation! I wasn't sure where exactly the pointer would be bound, thank you very much! Just making changes until you get the code to compile doesn't really help you much. I can almost guarantee this code will crash immediately. I'll try to go through this error by error: code:
code:
Now I don't see why twoDimStrVec has to be a pointer, but if you make it not be a pointer (i.e. just a plain vector<vector<string>*> instead of a vector<vector<string>*>*), all you need to do is change the parts that say "twoDimStrVec->" to say "twoDimStrVec.", and everything else can stay the same, like this: code:
Smackbilly fucked around with this message at 02:38 on Oct 12, 2008 |
# ¿ Oct 12, 2008 01:45 |
|
quote:While that really compact for-loop looks appealing, it won't run if it's empty - there's nothing in the table yet. The beginning is the end. I added a check to see if it was empty and made it into an if-else statement. But there's a problem. I added a lot of other code just to make sure the problem wasn't the method - it happens no matter which method I use, as long as it involves that specific for-loop and comparison. Here's the problem: you're re-using the same vecRows object over and over again for each row, and you're storing a pointer to it in the table. When you insert a pointer to the vecRows object into the table, you are not copying the contents of the vecRows vector into the table; you are only pointing back to it. So if you insert a pointer to vecRows into table slot 0, that means that when you later retrieve the contents of table slot 0, it just follows the pointer and reads whatever is currently in the vecRows object that you have a pointer to. So when you insert a pointer to the vecRows object, and then you then overwrite the vecRows object's contents with the next row, dereferencing the pointer in the table will then get you the new data in vecRows (because remember no copy was ever made). In short: because the table contains a pointer to the row vector, changing the contents of the row vector changes the contents of the table. This problem is really easy to avoid in the following manner: don't use pointers. There is absolutely no reason for you to be using pointers here. When I saw the code snippet you posted earlier, I assumed that there was some good reason why twoDimStrVec was a vector of pointers-to-vectors rather than a vector of vectors. I looked back through the thread to your initial post, and there's no reason at all for that to be the case. Just do this and all will be well: code:
Almost all of your confusion here seems to be because you are really eager to use lots of pointers when they are not necessary. No part of this process that we are helping you debug requires the use of any pointers. I suggest that you do some further reading on pointers (even the Wikipedia article or something) to help yourself understand what pointers really do and when/why they are necessary.
|
# ¿ Oct 12, 2008 10:15 |
|
Whilst farting I posted:It needs to be a vector of pointers to vectors of strings, though - this file is massive. This hit the nail on the head as to why I need to do it: Well, first of all I'm not convinced that using pointers will really make your program go all that much faster. This program is executing a loop of the form 1. read some data from disk, 2. move some stuff around in memory. Disk I/O is exponentially slower than memory access, so 90%+ of your program's time is going to be spent on step (1) rather than step (2) and making step (2) faster won't help all that much. But if you insist on using pointers, what you have to do is make vecRows into a pointer, and allocate new memory for it each time you start reading a new row. Declare vecRows as type vector<string>*, and replace the vecRows.clear() line with vecRows = new vector<string>(). Then, update the rest of the method so that vecRows[0] becomes (*vecRows)[0] (dereference the pointer to get the vector it points to before using the [] operator) and &vecRows becomes vecRows (no longer need to take the address, since vecRows is now itself a pointer). Now since you are allocating a new vector every time you read a row, you are no longer overwriting the contents of the vector that you have already stored a pointer to in the table. The downside of this is that you now have to worry about manually releasing that memory when it is no longer used, or else you will have a memory leak in your program. At minimum, this means defining a destructor for your class and having it iterate through twoDimStrVec, and call "delete *tblItr" (assuming that's what you call the iterator again. If your class provides a method to remove rows from the table, then you will have to call delete on the row pointers when you remove them from the table as well.
|
# ¿ Oct 12, 2008 19:36 |
|
Chuu posted:I've been doing Java mainly for the last couple years, and apparently did well enough on the interview to land a job . . . mostly in C++. I'm really struggling with a few things I seemly completley forgot. Some questions: Instantiation. It is vital however to note however that is not equivalent to "Object o = new Object()" in Java. In C++ "Object o;" instantiates an object on the stack - in Java all objects are on the heap, so this is something that has no Java equivalent. In C++ using the 'new' keyword instantiates on the heap (like Java), so even within C++, "Object o;" and "Object* o = new Object();" are very different. quote:2. When declaring constructors, I've been told several times never to initialize variables in the body because the virtual lookup table is not guaranteed to be filled, instead to do things like Object::Object() : m_thing(2){}. What if we need conditional logic to initialize some variables though? Using initialization lists (as in your little snippet) is usually preferred, but in most cases it is not required. It is strictly required only when you are initializing references (which cannot be reassigned in C++) or const variables. Otherwise, it's mainly just a convention, so members that need more logic in their initialization can be initialized in the constructor body. But I think you're a bit confused because this really has nothing to do with the object's vtable. The rule having to do with vtables and constructors is not to call virtual methods from constructors (since due to the incomplete vtable the call will not do what you want it to). You can do pretty much anything in a constructor body except call virtual methods. quote:3. In c++, how do you declare an object without a name? For example, what's the c++ equivalent of "throw new Exception()" in java. The equivalent to "throw new Exception()" is "throw new Exception()". That's perfectly valid C++ [edit: assuming you have a class called Exception]. Except you will probably want to "throw Exception()" instead in C++ since because C++ has no garbage collector, instantiating your exception on the heap (with 'new') means that at some point you have to explicitly deallocate it (with 'delete'), which can get real tricky real fast with exceptions. quote:4. About using delete. std::string a("hi"); delete(&a);. Why does this blow up? Because a is on the stack, and delete works on things that are on the heap. Only delete things that were instantiated with 'new'. Stack variables are automatically cleaned up when they go out of scope. quote:5. Let's say I have something like the following in Java: Remember that in C++ polymorphism only works with pointers and references. When you call "new This_object_implements_FOO()", you generate a pointer to an object of type This_object_implements_FOO, but then you try to assign that pointer to an object on the stack called 'foo', and that fails. This is what you want: code:
A side note: references and pointers are a bit tricky when coming from Java to C++ because in Java, every object variable is something that's kind of like a C++ pointer and kind of like a C++ reference. It's like a C++ pointer in that you can reassign what object it points to, but it's like a C++ reference in that you do not have to manually deallocate its storage, and you cannot do memory arithmetic with it. But remember that java has absolutely no equivalent to an object-on-the-stack, which is what you get when you write "FOO thingie" instead of "FOO* thingie". quote:7. I hope it's obvious what I'm trying to do here. What's the syntax to do it correctly? a->processMessage(std::string("Message")); (I know this is generally very bad form because you might loose the reference to delete the string.) There's nothing wrong with that. You are not creating a reference to anything there (that's Java thinking, not C++). std::string("Message") creates a temporary string object on the stack, which will go out of scope and be automatically cleaned up when the function call returns. Also, why are you writing std::string("Message") and not just "Message". There is automatic conversion between string literals and std::strings, so if a function wants a std::string, you can give it a string literal. Smackbilly fucked around with this message at 03:29 on Oct 25, 2008 |
# ¿ Oct 25, 2008 03:09 |
|
Janin posted:The size of a class is not variable, but fixed at compile-time. The issue is one of pointers. If you have an object that contains allocated memory but does not define an assignment operator, and then assign it to another object, the two distinct objects will share a memory buffer. This is almost certainly a bad idea. This describes one of the two problems with assigning objects that are neither POD nor have a specialized operator=, namely the problem that occurs here: code:
But this problem doesn't occur in this scenario: code:
However, both scenarios have a second problem: the left-hand-side destructor (which presumably deallocates the buffer) is not called when you overwrite it through default assignment, so the pointer to the original buffer allocated to a is lost, and you have a memory leak. This is the solution to both problems: quote:To fix it, define operator=() and have it copy the memory buffer into the new object.
|
# ¿ Oct 26, 2008 01:48 |
|
Running With Spoons posted:Here's a hard one for you guys : Your compiler might be interpreting the literal as a long and not a long long. Try changing "223344556677" to "223344556677LLU".
|
# ¿ Oct 26, 2008 02:25 |
|
|
# ¿ May 8, 2024 00:34 |
|
slovach posted:Why does something like this go into an infinite loop when you enter something over 50 characters? Take a look here: http://www.cplusplus.com/reference/iostream/istream/getline.html quote:n When the fail bit is set, all further input actions fail until you clear it (with std::cin.clear())
|
# ¿ Oct 26, 2008 02:36 |