Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
more falafel please
Feb 26, 2005

forums poster

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 example:
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
}
is there an option for the debugger to show that instead of COPY_PMV(pointer,pointer) ?

This will work if adst is an array, but not if it's a pointer (and not if it's an array that's degraded to a pointer in the current scope).

First off, you should use memcpy() or std::copy (if C++), because they're generally optimized beyond what you're going to write.

But if you want to debug this, I would suggest putting printfs/couts/however you log in the macro itself.
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
  { \
    printf("nn=%d &(adst[nn])=%p &(asrc[nn])=%p asrc[nn]=%d\n", nn, &(adst[nn]), &(asrc[nn]), asrc[nn]); \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
  } \
}

Adbot
ADBOT LOVES YOU

more falafel please
Feb 26, 2005

forums poster

Entheogen posted:

when i do a left shift, does the left most bit get sent to some carry register? on x86 machines, what would be the name of it?
I guess same would go for the right shift and right most digit.

I know how this works in PIC Micro controller, but I have no idea of how i would go about using it in C or assembler for x86.

If this isn't really performance-critical (like you're trying to avoid a couple more instructions and a jump per shift), I would go for the sure-fire cross-platform approach and check if the highest (or lowest for right shift) bit is set, and if so, bitwise-or it on to the lowest(/highest) bit of the result of the shift.

more falafel please
Feb 26, 2005

forums poster

Lexical Unit posted:

Let's say that now I want to make my container exception safe. I'm not sure where I can find information on what parts of the STL are exception safe (and at what level). If anyone can recommend a book or website that would help in this area please do. I have Sutter's Exceptional C++, just not on hand at the moment, so if that's good enough just let me know. I can go re-read it now that most of it isn't over my head.

In the mean time my immediate quandary involves conceptually reassuring myself that the following is no-throw guarantee exception safe:
code:
template< /* ... */ >
class trie
{
/* ... */
	private:
		typedef trie* trie_node;

		struct trie_node_delete
		{
			void operator()(trie_node const &node) throw()
			{
				delete node;
			}
		};

		struct trie_node_less { /* ... */ };
		typedef std::set<trie_node, trie_node_less> subtrie;

		subtrie children;
};

template< /* ... */ >
trie< /* ... */ >::~trie() throw()
{
	for_each (this->children.begin (), this->children.end (), trie_node_delete ());
}
What I'm unsure of is what exception guarantees does for_each(), begin(), end(), and other functions that those functions entail give me? Is this exception safe or not? If it is, do I have the no-throw guarantee?

From the horse's mouth: http://www.research.att.com/~bs/3rd_safe.pdf

more falafel please
Feb 26, 2005

forums poster

Space Duck posted:

I haven't touched C++ in a couple of years, so maybe I'm just missing something obvious, but this has me stymied.

I have a class I'm using to log events from my app, imaginatively named Log.

What I'm trying to do is have a container class (QueueRunner) that monitors and trigger events from a queue, and log those events, failures, etc.

I have a constructor in QueueRunner that takes a Log object, and from there, I can write whatever I want to the log:
code:
QueueRunner::QueueRunner (const Log &logTarget){
	eventLog = logTarget;
	eventLog << "Queue runner started.";
 
}
eventLog is a private data member of type Log. That code produces the expected entry in the logfile.

Any subsequent member of the QueueRunner class seems unable to write to the log, however. This code segment doesn't do what I'd expect:
code:
void QueueRunner::StartListening (char *address, int port){
	
	eventLog << "Opening Listen socket...";
It's not writing to the log file, but I'm not getting errors or segfaults, either. I know that the copy constructor for Log works, but I still think there's something I've overlooked.

Edit: the Log object and the QueueRunner objects are both instantiated in main().

Is eventLog of type Log or Log&? If it's Log, does Log's assignment operator work normally, so that if one is copied, the copy has the same log file open?

Do you have one QueueRunner object or several?

more falafel please
Feb 26, 2005

forums poster

Itaipava posted:

I thought the same thing, but I don't think it can be Log&. If it were the case, wouldn't eventLog -have- to be assigned to log in the constructor's initialization list?

I'm leaning towards Log's assignment operator copying the file stream because of that signature (const Log &).

Yeah, you're right about the reference assignment. He should be doing that anyway, though.

more falafel please
Feb 26, 2005

forums poster

Ari posted:

The question comes up pretty often as to the de facto library of books for learning various programming languages and concepts. In my experience reading threads discussing them and reading several of the books named, I think the general goon consensus is that Eckel's Thinking in C++ is the best one to pick up C++. But why are you learning both C and C++ at once?

Also Koenig's Accelerated C++: http://www.amazon.com/Accelerated-Practical-Programming-Example-Depth/dp/020170353X

more falafel please
Feb 26, 2005

forums poster

Red Oktober posted:

I'm currently getting started in C, by using it to write a compiler of sorts (its for an assignment).

Much of the code is generated already by BNFC (from the grammar I've written) , but I need to edit it to traverse my tree and do stuff.

My question is what is a good development environment to start off in C?

I've been using eclipse for java, but the C version doesn't seem to be as usable.

What would you all recommend?

I'm using Mac OS X, if it matters.

I'd suggest taking this opportunity to learn about working without an IDE, especially since you're getting started with C. IDEs tend to abstract away a lot of important details about the C/C++ compilation model, which may come back to bite you later.

I would say to find a text editor that you like -- TextMate seems to be the favorite on OS X for just about everyone except the Vim users, or Vim if you want to be a real programmer^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H learn Vim. Then learn to use gcc and make, enough to write a simple Makefile.

more falafel please
Feb 26, 2005

forums poster

I say make and not autotools (or a better build system like CMake, SCons, or Boost.Jam) because it's simple and you're more likely to run into that, at least in the C/C++ world, than something else.

For a simple project with a few source files, a Makefile would look like this:
code:
# set variables for the compiler and flags
CC = gcc
CFLAGS = -g

# the space-separated list of source files
SOURCES = file1.c \
          file2.c \
          file3.c \
          main.c

# substitute .o for .c in $(SOURCES), get the list of object files 
OBJS = $(patsubst %.c,%.o,$(SOURCES))

# typing just "make" will make program
all: program

# program depends on all the objects and is built by the rule below
program: $(OBJS)
<tab> $(CC) $(CFLAGS) $(OBJS) -o program

# file1.o depends on file1.c and file1.h, $< will expand to file1.c and $@ to file1.o
file1.o: file1.c file1.h
<tab> $(CC) $(CFLAGS) -c $< -o $@

# same, but file2.o depends on file2.c, file2.h, and file1.h (assume file2.c includes file1.h)
file2.o: file2.c file2.h file1.h
<tab> $(CC) $(CFLAGS) -c $< -o $@

# same, but file2.o depends on file3.c, file3.h, and file1.h (assume file3.c includes file1.h)
file3.o: file3.c file3.h file1.h
<tab> $(CC) $(CFLAGS) -c $< -o $@

main.o: main.c file3.h
<tab> $(CC) $(CFLAGS) -c $< -o $@
Haven't tested that, but it should basically work.

more falafel please
Feb 26, 2005

forums poster

HB posted:

What about a project with 40 source files and multiple targets?

At some point you just want to let the computer take care of it.

He's just getting started, I doubt that's going to happen. At any rate, I think one of the reasons you should use make is to learn when you shouldn't :)

more falafel please
Feb 26, 2005

forums poster

tef posted:

Also,

[code]
str = (char *)calloc(strlen(visitIdent(_p_->u.stm_.ident_))+2, sizeof(char));

Should be:
str = malloc(strlen(visitIdent(_p_->u.stm_.ident_))+2);
[code]

As sizeof(char) is always 1.

calloc() initializes memory to 0, while the contents of memory returned by malloc() are unspecified. Other than that, though, they're equivalent.

more falafel please
Feb 26, 2005

forums poster

GT_Onizuka posted:

Oh wow, that certainly helped out quite a bit. I'm getting some errors, but they seemed to be related to the libraries. Considering how old things are, I suppose I shouldn't be too surprised. Thanks again, I'm almost on my way!

EDIT: I know this is a long shot, as it's some random library, but I figure it's worth a shot. Here's the error I get:
code:
plotview.o: In function `Min_circle_2<Point*>':
/usr/include/CGAL/Min_circle_2.h:326: undefined reference to `CGAL::default_random'
plotview.o: In function `void CGAL::circumcenter_translateC2<float>(float const&, float const&, float const&, float const&, float&, float&)':
/usr/include/CGAL/constructions/kernel_ftC2.h:60: undefined reference to `CGAL::assertion_fail(char const*, char const*, int, char const*)'
plotview.o: In function `CGAL::Min_circle_2<CGAL::Min_circle_2_traits_2<CGAL::Cartesian<float> > >::compute_circle()':
/usr/include/CGAL/Min_circle_2.h:263: undefined reference to `CGAL::assertion_fail(char const*, char const*, int, char const*)'
collect2: ld returned 1 exit status
make[3]: *** [wcurve] Error 1
make[3]: Leaving directory `/home/ynadji/wcurve/wcurve'
make[2]: *** [all-recursive] Error 1
make[2]: Leaving directory `/home/ynadji/wcurve/wcurve'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/ynadji/wcurve'
make: *** [all] Error 2
All the errors seem to be within CGAL, so I haven't the slightest clue what's going on. Any ideas?

It looks like either the headers are out of date with the libraries you're linking in (unlikely), or you're not linking in the library correctly.

more falafel please
Feb 26, 2005

forums poster

Incoherence posted:

erase takes an iterator parameter. You probably want alphabet.erase(alphabet.begin()+j). Why is it this hard? Because the STL is weird.

Because iterators are better. Why? 'Cos. :colbert:

more falafel please
Feb 26, 2005

forums poster

Thug Bonnet posted:

No, that's what I'm asking! :) I'm just kind of curious, honestly. But how would the program know "where it is" in memory, how large it is, etc. Also, I assume it's not necessarily contiguous..

That depends on the OS. Also, these will be logical addresses, relative to the page table for your application, so they're basically meaningless outside, unless you can run in kernel mode or something.

But yeah, it's not going to be contiguous, you'll have different segments for the actual program code, static data, stack, and the free store.

edit: crap, I missed that page 6 existed, ignore me.

more falafel please
Feb 26, 2005

forums poster

xobofni posted:

Really stupid question here about pointers in C.

This code runs just fine.
code:
int main ()
{
    char a[] = "hello world";
    a[0] = 'b';
    return 0;
}
This code crashes.
code:
int main ()
{
    char *a = "hello world";
    a[0] = 'b';
    return 0;
}
I thought those declarations were exaclty the same, but apparently they are not. What am I missing here?

There's two issues here, one that addresses your immediate problem and one that will clear some things up for you.

In the first case, what's happening is you're declaring an array of char (actually, an array of 12 chars), and filling it with 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0'.

In the second case, you're taking a pointer and assigning it the address of a string literal which the compiler embedded into the executable somewhere. Generally, those string literals are in read-only segments of memory.

The second point is that pointers and arrays are not the same thing: http://c-faq.com/aryptr/

more falafel please
Feb 26, 2005

forums poster

Mr VacBob posted:

If you're debugging an optimized program, the debug info is probably wrong and giving you nonsense answers.

This. Try it with optimizations off, or try printing the values you need instead of trusting the debugger, if you need those optimizations for debugging.

more falafel please
Feb 26, 2005

forums poster

Hyphen-ated posted:

I am using VC++ 2005 express. I have sections of code that are #if'ed out sometimes. When editing this code, VC++ decides to gray it out and disable "go to definition" and friends in the context menu. This makes it more difficult to edit this code, which does actually get compiled sometimes. I would like it to treat all code as live code regardless of whether it looks like it will be compiled.

I can't find anything relevant in any of the config screens. How do I do this?

e: I can make the code not be grayed out from tools>options>text editor>c/c++>formatting, but that doesn't enable "go to definition"

Visual Assist can handle this, and it's Go To Definition isn't retarded like VS's is. Of course it's also money.

more falafel please
Feb 26, 2005

forums poster

Drx Capio posted:

It can't. The compiler MUST know the size of One in order to compile Two. It can be done with a level of indirection, though:

code:
class One;

class Two
{
  One* one;
};
This works because pointers to any type are always the same size, and the compiler just needs reassurance that 'One' isn't a typo.

It's dumb, but what it was suggesting was:
code:
// One.h
class One
{
    int x;
};
// end One.h

// Two.h
class Two
{
    One one;
};
// end Two.h

// main.cpp
#include "One.h"
#include "Two.h"

One one;
Two two;

int main()
{
    ...
}
But gently caress that.

more falafel please
Feb 26, 2005

forums poster

floWenoL posted:

Honestly that's not a very large project; have you tried building one of Firefox, KDE, or OpenOffice lately? Anyway, the issue is not the from-scratch build time, but the one-line-header change build time and from making sure that that isn't approximately equal to the from-scratch build time.

On my last project (about 1.5M lines of C++), cleaning up headers reduced our full build from about 4 hours to about 20 minutes, and reduced the frequency of full builds from about once a day on average to about once a week on average. Incremental builds were still about 5 minutes, mostly because of linking, but when you have that much code that needs to be statically linked, there's not much you can do about link times.

Most of this was due to the braindead way that the Unreal Engine generates headers from script classes -- all script classes belong to a "package," which is just a directory containing each of those script classes. For a package such as "Engine," there are about 100 script classes. Instead of generating one header for each of these, stock UE3 generates "EngineClasses.h" with all the declarations in one place (presumably so they don't have to worry about those pesky "dependencies" everyone keeps going on about). So you can guess how many C++ files include EngineClasses.h. We changed the script compiler so it generated a header for each class, and then started including only the headers necessary for each C++ file. That alone reduced our build times by about 90%. YMMV, obviously.

more falafel please
Feb 26, 2005

forums poster

6174 posted:

I've got a template function in which I'm doing a comparison like:

code:
if (number < 0) {
    number *= -1;
}
number is of type T. When T is an unsigned type the compiler gives me a warning:

../shared/number_stuff.h:102: warning: comparison of unsigned expression < 0 is always false

Is there anyway I can reasonably make these warnings go away? I tried enclosing it in an if (numeric_limits<T>::is_signed) block, but the compiler still complains.

Since numeric_limits<T>::is_signed is a compile-time constant, you should be able to make use of SFINAE to make one specialization for signed types and another for unsigned types. Otherwise, you can just turn off that warning with a #pragma around that block or for that file on the command line, but I'm pretty sure SFINAE is the proper way to do it. Concepts would make this easier.

more falafel please
Feb 26, 2005

forums poster

That Turkey Story posted:

Oh my lord... I hope that isn't what he was using std::vector for!

To be fair std::vector is a really dumbass name, WTG Bjarne.

more falafel please
Feb 26, 2005

forums poster

SintaxError posted:

I could be wrong, but I don't think your remove function should be declared/defined as const.

Yes, although the node_count = node_count - 1; shouldn't compile like this anyway. But yeah, remove shouldn't be const.

more falafel please
Feb 26, 2005

forums poster

Avenging Dentist posted:

It is an issue. I'm assuming the "converting NULL to double" error occurs at return NULL; in your code. That's bad because NULL isn't a valid value for non-pointer, non-integral types. It's performing an implicit conversion from a pointer (integer) type to the type of the elements in your list. Think about what would happen if there is no such conversion...

If you can change the signature of the function, I would return a bool instead of a T. There is no generic "bad" value for all types in C++. However, since your function already takes the element to remove, the caller already knows what element will be removed, and returning it is redundant. I would return true if the element was found and removed, and false otherwise.

more falafel please
Feb 26, 2005

forums poster

KaeseEs posted:

If it's an option, replace cout with cerr while debugging (STDERR is unbuffered). Otherwise, look up setbuf(3).

Sending std::flush or std::endl (flush with newline) to an output stream will also flush its buffer.

more falafel please
Feb 26, 2005

forums poster

vanjalolz posted:

Pointer and int are usually the same size though...

NEVER assume this. You have no idea how many times this comes up. If you want your code to compile on 64-bit, DO NOT ever assume this. Like, ever.

Ever.

more falafel please
Feb 26, 2005

forums poster

Smackbilly posted:

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.

It doesn't, really. All you need is a list of packets you have sent out but not received ACKs for yet. When you receive an ACK, remove that packet from the list. Also keep track of the last sent time and resend it every so often. Also, you can average the total round trip time of the last, say 10 packets, and use that as the timeout interval, to avoid sending to frequently or not frequently enough depending on network conditions.

more falafel please
Feb 26, 2005

forums poster

Zombywuf posted:

Why are you emulating TCP?

TCP is not always necessary.

more falafel please
Feb 26, 2005

forums poster

HB posted:

Lots of games using UDP with a very thin reliable layer on top of it. It can be tweaked to better match their traffic patterns (small packets, no bulk transfers, compensation for loss at the application layer) than TCP.

TCP is way, way, way overkill for most applications. For most applications, it doesn't matter, because the hit you take for using TCP isn't big enough to worry about. There are some applications, games being one of them, where most of the time, you want to reduce bandwidth as much as possible and not waste processing time in the OS doing more checking than you need. Also, many network protocols are not stream-oriented, which leads to building a "message" structure analogous to the underlying packet structure inside the TCP stream, which is in turn on top of the packet structure.

I don't have any idea if a reliable UDP layer is the right tool for Smackbilly's protocol, but he apparently has no control over it. But it's not "emulating TCP" any more than an RDBMS is "emulating a hash table".

more falafel please
Feb 26, 2005

forums poster

floWenoL posted:

On the other hand, it introduces an invalid value (kNumWhatever) that is treated like a valid value.

Plus GCC on overly paranoid settings will complain if you do this:
code:
enum Direction { North, South, East, West, kNumDirections };

void DoWork(Direction dir)
{
    switch (dir)
    {
        case North:
            DoNorthWork();
            break;
        case South:
            DoSouthWork();
            break;
        case East:
            DoEastWork();
            break;
        case West:
            DoWestWork();
            break;
    }
}
warning: enumeration value kNumDirections not handled in switch

But you should be putting default: blocks in switch anyway.

more falafel please
Feb 26, 2005

forums poster

chutwig posted:

Okay, I understand my first mistake; forgetting that the pointer is its own type with a different size from what it points to.

That being said, I guess I need to issue a malloc for bs_tm and then have it write to that, and probably also malloc the other pointers before I write to them.

I know I don't completely understand pointers yet; that's why I'm undertaking this now, so that I become more aware of manual memory management rather than simply letting the computer always do it for me. Just telling somebody to read K&R again doesn't help much when dealing with something like pointers that is very complex.

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.

more falafel please
Feb 26, 2005

forums poster

slovach posted:

It's pretty simple actually.

code:
#include <windows.h>

char target[] = "\\test.exe";
char path[MAX_PATH];
STARTUPINFO         si = { 0 };
PROCESS_INFORMATION pi;

int main(){
	si.cb = sizeof(STARTUPINFO);
	GetCurrentDirectory((MAX_PATH - sizeof(target)), (LPSTR)&path);
	lstrcat((LPSTR)&path, (LPSTR)&target);
	CreateProcess((LPSTR)&path, NULL, NULL, NULL, FALSE, 
				  NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
}
edit: I like how my pi turned into an actual PI... at least that's what I think it did? wtf.

Looks like at least some browsers (Safari at least) treat & p i ) ; as & p i ;, which should render as the pi symbol.

more falafel please
Feb 26, 2005

forums poster

floWenoL posted:

What do you guys think of this?

There's some stylistic issues I don't agree with that people have been arguing about for 30 years (wtf uses 2 spaces) but other than that I think it's pretty sane.

Some day I'll post the tale of mustDeref() and make you all converts.

more falafel please
Feb 26, 2005

forums poster

Avenging Dentist posted:

Also the "no using in .cc files" rule is laffo. That's pretty much the only place you should have using declarations.

I understand it. They also say to eschew abbreviations in naming. using declarations are just abbreviations, really.

I'm not saying I particularly like it, but I don't really have an opinion.

more falafel please
Feb 26, 2005

forums poster

That Turkey Story posted:



Well put.

more falafel please
Feb 26, 2005

forums poster

ZorbaTHut posted:

Real-world numbers tend to follow a power distribution, and in power-distribution-land, that extra bit increases your number's range by a piddling 3%. That's usually not anything worth mentioning.

You have absolutely no understanding of what you're talking about.

edit: OK, I think it's just phrased badly and you're talking about power distribution. I thought you were actually arguing that adding bits to a number increased the range of values the number could store linearly instead of exponentially.

more falafel please fucked around with this message at 21:23 on Jul 2, 2008

more falafel please
Feb 26, 2005

forums poster

ZorbaTHut posted:

It would be hard for me to disagree with more points here :v:

First, the only thing I agree with: Yes, using iterators bypasses the issue of sign nicely. Sometimes, however, that's just not practical - I'm giving a small example of a situation where it breaks in an unexpected and subtle way, not a fullfledged example of a case where it's an inevitable bug (since I don't believe those exist.)

And it's a bad example, because the simpler, more correct solution would be to use iterators, in which case you would have had to go way out of your way to introduce a bug like that.

ZorbaTHut posted:

It's just not something that ever comes up - I consider this to be well within the bounds of "this never happens".

It's those subtle bugs -- like the ones that can be easily introduced by using offsets instead of iterators, that make "this never happens" turn into "But I never thought that would happen". Every simple programming error that can be made, will probably be made, often by you. Use a simpler and less error-prone solution where possible.

ZorbaTHut posted:

And even if it does, I'd say a better solution would be to use a longer signed type, like "long" (which will be 64-bit on virtually any sane system where .size() can be 1<<31)

I'm not aware of any 32-bit system in which long is 64-bit, is that what you're saying?

"ZorbaTHut posted:

or "long long" (which will be 64-bit and which is nearly part of C++), not an unsigned type, for the same power-distribution reasons I mentioned beforehand.

Well, "long long" technically isn't a part of C++. Compilers/runtimes in general can deal with it, but 64-bit long long on 32 bit systems generally means software manipulation, which is significantly slower. But the real problem here is that you're saying "adding 1 more bit to make sure you don't overflow/underflow is silly, you should add 32 bits." It is silly to add one bit, but just extending that to 32 bits is almost as silly -- it's a variation of throwing hardware at the problem, when the problem only exists because you're not using the correct method in the first place.

ZorbaTHut posted:

Also, saying "if you write it correctly, it always works! :hurr:" is kind of meaningless, because obviously it'll work if you write it correctly. What I'm getting at here is that unsigned variables make it much easier to introduce subtle unexpected bugs, thereby either reducing the chance that you'll write it correctly or increasing the amount of effort and time it takes to write it correctly (take your pick) while signed variables avoid a small but significant class of errors.

What he's saying is that using the correct approach means that your chance of not writing it correctly is decreased. Use signed ints for ints that will always be in a particular range that can be negative, use unsigneds for ints that will always be in a particular nonnegative range, and don't use ints when there's a more appropriate and less error-prone abstraction available to you.

more falafel please
Feb 26, 2005

forums poster

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, the preprocessor does text substitution only. It's not compiling or optimizing anything.

more falafel please
Feb 26, 2005

forums poster

Entheogen posted:

how exactly does one link statically instead of dynamically in c++?

the only way to link dynamically would be against a DLL or SO file?

when I include .h files in my C++ program and it is linked against a .lib file is that static linking by default?

Depends on your build environment. The headers have absolutely nothing to do with how the library is linked.

Look at it this way: each translation unit (for all intents and purposes, a .cpp file after the preprocessor is done with it) you compile defines a set of exported symbols, like main, MyCoolFunction, etc. There's also a set of symbols it references that are not defined in that translation unit: strcpy, SomeLibraryFunction, etc. Each translation unit is compiled into an object file, usually .o or .obj.

The linker's job is to take several object files (and static libraries, which are just collections of object files, .lib or .a generally), resolve the symbols referenced and defined in them, and cram them all together into an executable where all the symbols reference the correct code/data.

When you link against a static library, all the code and data from that library referenced by your program gets copied into the executable. When you link against a dynamic library, the linker generates a little routine that runs before main that loads the dynamic library through the OS and resolves the referenced symbols in that library with the ones in the program.

So I guess in a roundabout way, yes, when you link against a .lib, that's static linking, and all the code you use in that .lib file ends up in your executable.

more falafel please
Feb 26, 2005

forums poster

Avenging Dentist posted:

Pointers are very important, since they allow objects to have other-than-lexical scope. If you make an object on the stack in a function and return a reference to it, that object will get destructed when the function returns. It's also necessary for dynamically-sized data.

Yes. Pointers are also necessary for referencing objects that may be invalid, since they can be NULL, and references (for any defined behavior) can't be. Also, references can not be reseated to refer to a different object - once they're defined they point at that object forever until they go out of scope.

That said: you should use references over pointers whenever feasible.
http://www.parashift.com/c++-faq-lite/references.html#faq-8.6

(As an aside, you would probably benefit from reading large portions of the C++ FAQ Lite, as well Scott Meyer's Effective C++)

quote:

I don't use "design patterns" as such for any of my projects. Granted, a design-pattern nerd will probably look at my code and say "oh well this is a clear example of design pattern X", but I just write code in whatever way I find to be most elegant.

The most important part of the Gang of Four Design Patterns book is the prologue, where it says that the purpose of the book is to create a common language for talking about patterns that "naturally occur" in object-oriented programming. In other words, every competent programmer will, at some point, decide that they need something like the Strategy pattern, but instead of describing exactly how they accomplish it in code, they can say "I use something like the Strategy pattern here."

Design patterns are NOT a set of idioms for you to put in your programs. I would even advise against specifically referring to the classes that implement things like design patterns by their pattern name (for instance, don't call your classes FooStrategy and BarStrategy). For one thing, it adds little information: the code you're writing should make it pretty obvious that you're using something like Strategy. But the main problem is that it will lead to a tendency to write code that conforms more closely to the Go4 book than to your actual problem. Again, the usefulness of design patterns comes from the fact that it lets programmers talk about solutions to design problems with a common language -- not a starting-off point where you just fill in the details. If you try to do this, you'll end up with patternitis and over-engineer everything about your program. In other words, you'll end up as a Java programmer.

quote:

God yes. This isn't Java, and it makes no sense to have a class that can't actually be instantiated. Use a namespace if you need to encapsulate all the functions, or just leave them global if you don't care.

Again, don't overthink it. The main reasons you use classes are for associating code with the data it operates on, encapsulating that data (implementation details) and hiding it behind the interface, and polymorphism. If you don't need any of these, then the only reason you're putting things in a class is so they're not in the global namespace. Ok, then put them in a namespace. If you don't want clients to be able to call certain functions directly (what you would put private in a class), then put them in the anonymous namespace so they won't be visible outside the file they're defined in.

Classes are a tool that C++ programmers have. They're a very powerful tool, but they're by no means the only tool.

quote:

They do add overhead, in that a function that may throw needs to be compiled such that it can "return" at arbitrary points in its execution. Additionally, exceptions require some form of RTTI (run-time type identification) in order to inspect the exception's type when caught.

That said, if you have to ask, it's not important for what you're doing.

Yeah, there's definitely overhead involved. The biggest problem is that using exceptions in one place in a program essentially means that the rest of the program has to be using RTTI and have exception-handling code compiled in.

But generally when you try to solve a similar problem without exceptions, you end up with a half-assed complicated ugly version of exception handling. Unless you're talking about game development (like real AAA-title game development), real-time trading, or something else that needs to be super-loving-fast and use as little memory as possible, just use exceptions. Putting it in perspective: if 1ms doesn't sound like a lot of time, use exceptions.

more falafel please
Feb 26, 2005

forums poster

Centipeed posted:

I've checked out Bjarne's book on C++. It seems comprehensive. I've also taken a look at Thinking in C++.

Is there a book I can get hold of that takes C++ programming and explains each and every detail in layman's terms? Or gives metaphors to help understanding. I find myself reading some sentences or paragraphs in "The C++ Programming Language" several times in an effort to digest them.

A book which can be used as sort of a reference for explaining concepts in plain English rather than relying on other programming concepts would definitely be helpful.

Like, is the C++ For Dummies book any good? I'd imagine that would break things down well enough.

Accelerated C++:
http://www.amazon.com/Accelerated-Practical-Programming-Example-Depth/dp/020170353X

Adbot
ADBOT LOVES YOU

more falafel please
Feb 26, 2005

forums poster

Entheogen posted:

code:
#define FOREACH(_it,_l) for(__typeof((_l).begin()) _it=((_l).begin());(_it)!=(_l).end();(_it)++) 

You don't even need BOOST_FOREACH for this, just use std::for_each. It'll work for anything that has a T::iterator type (and begin(), end() and operator++ on the iterator), and makes way more sense than using the macro version.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply