Thread: Homework Problem About Pointers

  1. #16
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Ashl7 View Post
    @grumpy:
    I know the definition that you see there was a test, I think this one should work, but it does not:

    Code:
     ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can."<<endl;
        
         return outs ; 
    }
    For a const pointer, getContents() and other member functions being called here also need to be declared const.

    Quote Originally Posted by Ashl7 View Post
    I know the way I write these codes are not correct, but I'm new to this...if there's a mistake, teach me, instead of mocking me LOL
    I didn't mock you at all. I described characteristics of your definition of the operator<<() for your class, highlighting what I consider to be problems.

    Admittedly, I didn't describe solutions to those problems, but that isn't personal. It's just a reflection of limited time I had at my disposal when I posted, and that it's often difficult to know where to start with such explanations to a beginner, nothing more. If you follow advice of other posters since, you will have addressed a number of the problems I pointed out.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  2. #17
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by MutantJohn View Post
    Wait, try putting inline in front of the definition.
    This will not work since the function is undefined, not duplicated.
    Ashl7: Avoid inline for now. It can cause a lot of damage if used improperly.

    Now let's take a look at that message:
    Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main
    If we gleam the error message, we can see 3 pieces of useful information:
    - Red color: This is the linker saying: I can't find this function. This happens when you declared a function (hence the compiler saying: I can't find this function, but OK, I trust you) but didn't actually define it.
    - Orange color: This tells the the function that was not defined. It's very verbose, but look at the specific parts. It says it returns an basic_ostream (which is just another name for ostream), it's called operator << and it takes an ostream and a const SodaCan&. So that is the function you must look for and define. Make sure it has the right name, right return type and the right parameters.
    - Red color: This tells you the function where the function was called from, the function that the linker couldn't find.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #18
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Elysia View Post
    - Red color: This tells you the function where the function was called from, the function that the linker couldn't find.
    Small correction

    - Blue color: This tells you the function where the function was called from, the function that the linker couldn't find.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  4. #19
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    This will not work since the function is undefined, not duplicated.
    Ashl7: Avoid inline for now. It can cause a lot of damage if used improperly.
    Ah, my bad.

    But Ashl, I've had issues in the past where I included the overloaded << operator in a header file and the only to make it all compile was to inline the function. Hence why Elysia pointed out the issue was not a duplication which is what inlining fixes.

    But if you were ever wondering, inlining takes a function and places the entirety of it in the place where the function is called.

    Consider :
    Code:
    #include <iostream>
    
    inline void print_message(void) {
        std::cout << "Hello, world!\n";
        return;
    }
    
    int main(void) {
    
        /*
             Without inlining, we call our print function and everything works fine
        */
    
         print_message();
    
         /*
              But using inlining, calling our function is logically equivalent to this
         */
    
         std::cout << "Hello, world!\n"; // the contents of the function are directly placed "inline"
        return 0;
    }
    It's supposed to make code faster, sometimes, because shifting stack frames might be more expensive. Wait, that's the reason, right? Because if you have a function that receives many parameters and has a return, it can be more expensive to pass everything back and forth than it can be just to have a giant function but that hurts readability so inlining is the solution. It makes everything readable while still avoiding the overhead of a function call.

    I also think most compilers still ultimately decide what will and will not be inlined. You writing "inline" is more like a suggestion. The compiler is the deciding factor because if you call the function a lot, the size of the executable grows and that can actually hurt performance more. I tried googling around for this and one of the reasons I saw was because it could invoke "paging" which I don't seem to know much of. But it seems like operating systems allocate memory to programs in fixed blocks and increasing the size of the executable means it would need more pages of memory? Does that even make sense?

    Anyway, Elysia's probably right.

  5. #20
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Ashl7
    It does not compile, it says : error C2662: 'SodaCan::getContents' : cannot convert 'this' pointer from 'const SodaCan' to 'SodaCan &'
    > Conversion loses qualifiers
    and here is where it tells me I have to fix:
    This is why I wrote in post #4:
    Quote Originally Posted by laserlight
    Note that some of your member functions are not const-correct, e.g., I would expect isEmpty and the getFOO functions to be declared const.
    Quote Originally Posted by Ashl7
    however I still get the error I was getting at first, I have not been able to compile it yet...
    In the future, after making changes to your code, post the updated code. It did not matter in this case, but keeping everyone on the same page can help.

    Quote Originally Posted by MutantJohn
    But Ashl, I've had issues in the past where I included the overloaded << operator in a header file and the only to make it all compile was to inline the function.
    Yeah, the key is that you defined the overloaded operator in the header file, hence breaking the one definition rule should the header be included in more than one source file... except that by declaring it as inline, the one definition rule was no longer broken.
    Last edited by laserlight; 06-03-2014 at 12:25 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #21
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I tried googling around for this and one of the reasons I saw was because it could invoke "paging" which I don't seem to know much of. But it seems like operating systems allocate memory to programs in fixed blocks and increasing the size of the executable means it would need more pages of memory? Does that even make sense?
    O_o

    I'd say the "instruction cache" would be easier to understand in considering the possible costs of `inline' functions.

    The "instruction cache" is barely different than your normal memory cache that lives on the processor. Essentially, the processor needs instructions from main memory, yet fetching individual instructions from RAM each step would be far too costly so the processors fetches a block of instructions and stores them in hardware offering far faster access.

    Let's say you have a few functions, `DoStuff#' and `DoUtility#', which are invoked each iteration in a crucial loop.

    The ideas behind "spatial locality" seemingly apply to the `inline' function. You might think that the utility functions being "inlined" would necessarily improve performance. The processor will, one may expect, see a cache and fetch benefit, increasing performance, by "storing" duplicated `DoUtility#' functions within each `DoStuff#' function. You might, for example, expect the absolutely necessary `DoSomething1' fetch to also acquire `DoUtility1' and `DoUtility2' with such an arrangement requiring fewer access to main memory.

    One function "inlined" exactly once isn't an interesting scenario so continue by also considering the `DoSomething2' function. The crucial loop in question also uses `DoSomething2' which needs `DoUtility1' and `DoUtility3'. We expect, as above, that `DoSomething1' "inlines" `DoUtility1' and `DoUtility2'. The `DoSomething2' function also "inlines" `DoUtility1' and `DoUtility3'. As you can see, two copies of `DoUtility1' need to exist in the "instruction cache" because the "inlining" prevents the conceptually shared resource from actually being shared. The "instruction cache" has a, in comparison to normal main memory, extremely limited size. You are placing the burden of storing duplicates for conceptually shared resources by "inlining" functions. The processor must, for the purposes of example, remove the implementation of `DoSomething1' from cache because the `DoSomething2' is too large to coexist.

    Of course, my example is extreme. The example shows a scenario where two parts of an implementation are mutually exclusive forcing the processor to alternately fetch `DoSomething1' and `DoSomething2' each iteration of a crucial loop. Following good programming practices, you are unlikely to naturally see such an extreme scenario, but the fact remains that the expectation of increased performance related to "spatial locality" is not reasonable for all functions.

    Happily, most programmers can safely ignore most of these considerations. Modern compilers are really quite good at balancing "spatial locality" and "shared implementation" when presented idiomatic code.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  7. #22
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    I tried googling around for this and one of the reasons I saw was because it could invoke "paging" which I don't seem to know much of. But it seems like operating systems allocate memory to programs in fixed blocks and increasing the size of the executable means it would need more pages of memory? Does that even make sense?
    O_o

    I'd say the "instruction cache" would be easier to understand in considering the possible costs of `inline' functions.

    The "instruction cache" is barely different than your normal memory cache that lives on the processor. Essentially, the processor needs instructions from main memory, yet fetching individual instructions from RAM each step would be far too costly so the processors fetches a block of instructions and stores them in hardware offering far faster access.

    Let's say you have a few functions, `DoStuff#' and `DoUtility#', which are invoked each iteration in a crucial loop.

    The ideas behind "spatial locality" seemingly apply to the `inline' function. You might think that the utility functions being "inlined" would necessarily improve performance. The processor will, one may expect, see a cache and fetch benefit, increasing performance, by "storing" duplicated `DoUtility#' functions within each `DoStuff#' function. You might, for example, expect the absolutely necessary `DoSomething1' fetch to also acquire `DoUtility1' and `DoUtility2' with such an arrangement requiring fewer access to main memory.

    One function "inlined" exactly once isn't an interesting scenario so continue by also considering the `DoSomething2' function. The crucial loop in question also uses `DoSomething2' which needs `DoUtility1' and `DoUtility3'. We expect, as above, that `DoSomething1' "inlines" `DoUtility1' and `DoUtility2'. The `DoSomething2' function also "inlines" `DoUtility1' and `DoUtility3'. As you can see, two copies of `DoUtility1' need to exist in the "instruction cache" because the "inlining" prevents the conceptually shared resource from actually being shared. The "instruction cache" has a, in comparison to normal main memory, extremely limited size. You are placing the burden of storing duplicates for conceptually shared resources by "inlining" functions. The processor must, for the purposes of example, remove the implementation of `DoSomething1' from cache because the `DoSomething2' is too large to coexist.

    Of course, my example is extreme. The example shows a scenario where two parts of an implementation are mutually exclusive forcing the processor to alternately fetch `DoSomething1' and `DoSomething2' each iteration of a crucial loop. Following good programming practices, you are unlikely to naturally see such an extreme scenario, but the fact remains that the expectation of increased performance related to "spatial locality" is not reasonable for all functions.

    Happily, most programmers can safely ignore most of these considerations. Modern compilers are really quite good at balancing "spatial locality" and "shared implementation" when presented idiomatic code.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  8. #23
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by hk_mp5kpdw View Post
    Small correction

    - Blue color: This tells you the function where the function was called from, the function that the linker couldn't find.
    Hey, what can I say? I like red.

    Quote Originally Posted by MutantJohn View Post
    ...But it seems like operating systems allocate memory to programs in fixed blocks and increasing the size of the executable means it would need more pages of memory? Does that even make sense?
    Yes, it does.

    You know the concept of virtual memory, right? The OS controls access to memory by handing out some kind of "non-existent" (i.e. "virtual") memory to programs. But it must also map this "virtual" memory to real memory. Now let's take this to the extreme. Say we have to translate every virtual byte to a physical byte. This would work by adding a fixed offset to every byte, sure. But that's how how memory management works. As applications use and release memory, fragmentation occurs. We can get around this by letting every virtual byte point to some physical byte but is not necessarily contiguous! Imagine the OS having to compact memory whenever fragmentation occurs. Horrible performance!

    But this scheme has its own disadvantage. So we can't use the same offset for every byte. That means we need an offset or physical address for every byte! Imagine the overhead! Clearly, this is an unacceptable waste of memory. So operating systems typically map virtual memory to physical memory for some blocks, which is a fixed number of bytes, so that only each block has to be translated. That is, every byte addressed within that block has the same offset. A typical size is 4K. Of course, some operating systems, such as Windows, allows applications to use other sizes that 4K when allocating memory (but this is not supported by C/C++, of course, as they have no concept of "virtual memory").

    Now, for the final approach. What happens when you try to run an application? Will the OS read all the instructions from the hard drive? Obviously not! That would be horrible for performance. Add to that that the CPU cannot fetch information from the hard drive to its caches. So what do we do? We load the binaries into memory. But with some large programs, fitting everything into memory can be very expensive! So what do we do? We try to use a technique such as load on demand which fetches parts of the executable into memory as it is read. This works hand-in-hand with paging as paging is partially used to ensure programs do not trample on other programs' memory and does not read/write non-allocated memory. So the OS allocates virtual pages for the application and marks them as non-readable. This causes a page fault whenever such a page is read. This causes the OS to fetch the information that should be in the page from disk.

    Following this logic, it is very possible to see how larger executable sizes can result in degradation of performance. Of course, with page files, if the OS is short on memory, it will write pages to the page files and evict the information from memory. That can cause parts of an application code to be unloaded from memory, causing another page fault if the code within that page is executed again. Otherwise the code typically stays in memory for as long as the application is running. Of course, part of the instructions contained in memory also end up in the CPU caches.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #24
    Registered User MutantJohn's Avatar
    Join Date
    Feb 2013
    Posts
    2,665
    Interesting. Thank you, Elysia.

    I was also considering the instruction cache as well as phantom highlighted but at the same time, I knew nothing of paging so that was an interesting and very easy to understand read.

  10. #25
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    Wow I totally missed that this thread went to the second page!
    First of all, thanks everyone for the comments.
    @Elysia, I decided to remove some of the codes that my teacher had in his driver.cpp file in order to make things clearer for myself(and you guys) to find out where the problem is from...I also removed some of the functions defined in header and implementation. It was just so messy...

    @laserlight: sorry if I missed your note, I read it, but I didn't know what you meants by getFOO() lol, but now I know...sure I'll be more clear about what I'm doing from now on

    here is the original driver file:

    Code:
    int main( ) {
    
    SodaCan myPepsi;
    SodaCan yourDietCoke;
    SodaCan bigGulp;
    SodaCan junk;
    
    bigGulp.setBrand( "Pepsi" );
    bigGulp.setSize( 128 );
    myPepsi.setBrand( "Pepsi" );
    myPepsi.setSize( 12 );
    yourDietCoke.setBrand( "Coke" );
    yourDietCoke.setSize( 12 );
    myPepsi.pourInSoda( 2 );
    yourDietCoke.pourInSoda( 3 );
    bigGulp.pourInSoda( 64 );
    
    /// junk should have 76 ounces
    junk = bigGulp + myPepsi;
    cout << junk;
    
    if (junk > bigGulp) {
      cout <<"junk’s bigger"<< endl;
    }
    if (junk >= bigGulp) {
      cout <<"junk’s bigger or equal"<< endl;
    }
    if (myPepsi < junk) {
      cout<<"myPepsi’s smaller"<<endl;
    }
    if (myPepsi <= junk) {
      cout<<"myPepsi’s smaller or equal"<<endl;
    }
    if (myPepsi != junk) {
      cout <<"myPepsi != junk!"<<endl;
    }
    if (myPepsi == myPepsi) {
      cout <<"equal test works"<<endl;
    }
    
    SodaCan * ptrCan = new SodaCan( "Coke", 25, 3 );
    SodaCan * nullCan = NULL;
    
    // be careful
    cout << nullCan << endl;
    cout << ptrCan << endl;
    
    cin >> ptrCan;
    // notice the difference
    cout << ptrCan << endl; 
    ptrCan->pourInSoda( 10 );
    /// notice the difference
    cout << ptrCan << endl;
    
    delete (ptrCan);
    // why can't I do this???
    // delete( nullCan );
    
    return( 0 );
    
    }

    and here is the new one, after I removed some of the codes I assumed are making problem:

    Code:
    int main( ) {
    
    SodaCan myPepsi;
    SodaCan yourDietCoke;
    SodaCan bigGulp;
    SodaCan junk;
    
    bigGulp.setBrand( "Pepsi" );
    bigGulp.setSize( 128 );
    myPepsi.setBrand( "Pepsi" );
    myPepsi.setSize( 12 );
    yourDietCoke.setBrand( "Coke" );
    yourDietCoke.setSize( 12 );
    myPepsi.pourInSoda( 2 );
    yourDietCoke.pourInSoda( 3 );
    bigGulp.pourInSoda( 64 );
    
    /// junk should have 76 ounces
    junk = bigGulp + myPepsi;
    
    
    if (junk > bigGulp) {
      cout <<"junk’s bigger"<< endl;
    }
    if (junk >= bigGulp) {
      cout <<"junk’s bigger or equal"<< endl;
    }
    if (myPepsi < junk) {
      cout<<"myPepsi’s smaller"<<endl;
    }
    if (myPepsi <= junk) {
      cout<<"myPepsi’s smaller or equal"<<endl;
    }
    if (myPepsi != junk) {
      cout <<"myPepsi != junk!"<<endl;
    }
    if (myPepsi == myPepsi) {
      cout <<"equal test works"<<endl;
    }
    
    SodaCan * ptrCan = new SodaCan( "Coke", 25, 3 );
    
    
    // be careful
    
    cout << ptrCan << endl;
    
    
    
    delete (ptrCan);
    // why can't I do this???
    // delete( nullCan );
    
    return( 0 );
    
    }

    I compiled the latter and there was no problem, it worked nicely
    so driver.cpp above works fine.

    Homework Problem About Pointers-untitled-png

    Also, the definition of my overloaded function was:
    Code:
    std::ostream& operator <<( std::ostream& outs, const SodaCan *can ){
    
         
         outs<< can->getContents() <<" ounces of " <<can->getBrand() <<" in a "<<can->getSize()<< " can.";
        
         return outs ; 
    }
    then I added these two lines to it(which was in the original Driver.cpp file by my teacher):

    Code:
    SodaCan * nullCan = NULL;
    cout << nullCan << endl;
    the program crashes...

    1) how do you suggest I escape this issue?! exception handling? if yes, I need some guidance on the subject, I know a little bit about it, but we have not covered it in class yet.
    2) Is it possible to overload << where the arguments are not pointers, while having the overloaded version of >> with pointers as arguments?

    I'm also trying to understand the conversation MutantJohn started and the comments followed by it...complicated stuff,god I'm so behind on these topics lol
    Last edited by Ashl7; 06-03-2014 at 11:27 PM.

  11. #26
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    Answer to No.2 question:
    apparently I can't do that! In the driver code by my teacher, we need to print an object of the class without using pointers
    Code:
    /// junk should have 76 ounces
    junk = bigGulp + myPepsi;
    cout << junk;
    So I added this definition to my implementation file
    Code:
       std::ostream& operator <<( std::ostream& os, SodaCan &my_can )
    {     
        os<< my_can.getContents() <<" ounces of " <<my_can.getBrand() <<" in a "<<my_can.getSize()<< " can.";
        return os ; 
    }
    and it gives me this error which Elysia analyzed earlier:
    Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main

    So, now I know why I couldn't run the program, however, I need both versions of operator << (with pointers as arguments, or regular variable) work in my program........thoughts?

  12. #27
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Ashl7
    and it gives me this error which Elysia analyzed earlier:
    Driver.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class SodaCan const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@ std@@AAV01@ABVSodaCan@@@Z) referenced in function _main
    Spot the difference:
    Code:
    std::ostream& operator <<(std::ostream& os, SodaCan& my_can);
    std::ostream& operator <<(std::ostream& os, const SodaCan& my_can);
    Normally, when overloading operator<< for an output stream, we use the latter since the object to be printed will not be logically modified by being printed. However, you defined operator<< as the former, but you probably forward declared it as the latter. Therefore, you still get the link error.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #28
    Registered User Ashl7's Avatar
    Join Date
    Oct 2012
    Posts
    57
    Quote Originally Posted by laserlight View Post
    Spot the difference:
    Code:
    std::ostream& operator <<(std::ostream& os, SodaCan& my_can);
    std::ostream& operator <<(std::ostream& os, const SodaCan& my_can);
    Normally, when overloading operator<< for an output stream, we use the latter since the object to be printed will not be logically modified by being printed. However, you defined operator<< as the former, but you probably forward declared it as the latter. Therefore, you still get the link error.
    uuugh! god!! I even declare it with const in my header file, but missed it in my definition....thank you!
    any thoughts on the second question?! a way to work with NULL pointer on this class?

  14. #29
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Ashl7
    any thoughts on the second question?! a way to work with NULL pointer on this class?
    You are referring to:
    Code:
    cout << nullCan << endl;
    right? If so, what does the statement mean? What does it mean to print a null pointer of type SodaCan*? What output do you expect? Remember, you are changing the usual semantics, so you must know what are the new semantics intended, otherwise no amount of advice will help other than "don't do this as your teacher is misguided".

    Note that delete nullCan is perfectly fine: delete on a null pointer is a no-op.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  15. #30
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    Remember, you are changing the usual semantics, so you must know what are the new semantics intended, otherwise no amount of advice will help other than "don't do this as your teacher is misguided".
    O_o

    @Ashl7:

    One of the best things about C++ reference semantics is not having to deal with the possibility of a null pointer. The idiomatic overload, using the `const Type &', allows you to expect a valid reference. You may overload for pointers if you wish, and placing the burden of the check for null within the `operator <<' implementation may seem reasonable, but you are reaching slightly beyond expected semantics by overloading for a specific pointer.

    The only standard behavior offering guidance for "new semantics" is found within the "stream operator" for `const char *' and a few utility overloads. The overload for `const char *' is somewhat unique for "stream overloads" in that the overload even exists. (The utility overloads do not print a value.) The history of C++ explains why the overload exists. The overload exists almost entirely for compatibility with expectations set by the inherited C standard.

    The semantics of all the standard pointer overloads which dereference the provided pointer is to not check for null. The implementation details do fall under "implementation defined"; an implementation which checks for null is conforming. Most implementations do not do the check at all, and the implementations which do check for null are conditionally altered such that the check only exist during debugging.

    The code in the diver is simply flawed. If the type was changed to a standard overload, such as `const char *', which would be dereferenced the application would crash because the client code, the driver, is incorrect.

    Code:
    const char * nullCan = NULL;
    cout << nullCan << endl; // effectively the same as `*0' which isn't a thing
    You should, without question, present the flaw to your teacher.

    The "new semantics" really are crucial.

    Code:
    const char * s1 = 0;
    const char * s2 = "";
    Consider please the difference between an empty string and a null pointer. The empty string, for one example, has a length while the null pointer does not because "length" is not a property of null.

    The difference between an empty, generic brand `SodaCan' and a null pointer is similar. The generic `SodaCan', for one example, will have a "store brand" while "brand" is not a property of null.

    Soma
    Last edited by phantomotap; 06-04-2014 at 12:05 PM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Homework Problem help!! Please.
    By arti in forum C Programming
    Replies: 10
    Last Post: 03-22-2013, 06:50 AM
  2. help!!!!!! pointers homework
    By ver_gon89 in forum C++ Programming
    Replies: 17
    Last Post: 11-24-2008, 12:23 AM
  3. homework problem Please Help!
    By alexwink in forum C Programming
    Replies: 24
    Last Post: 10-27-2006, 08:20 AM
  4. Replies: 27
    Last Post: 10-11-2006, 04:27 AM