This snippet can't run

Started by
6 comments, last by zaerl 16 years, 9 months ago
Today I was playing a little with smart pointers. I've accidentally written a wrong line of code. I have extrapolated the line from the main program:
#include <iostream>

namespace
{

struct foo
{
   void bar() const
   {
      std::cout << "hi there\n";
   }
};

template<class T> class not_so_smart_ptr
{
public:

   T* operator->() const
   {
      return 0;
   }
};

}

int main(int argc, char* const argv[])
{
   not_so_smart_ptr<foo> test;
   test->bar();                  // <---- this can't be
   return 0;
}


This snippet really print "hi there" but: *) operator-> return 0. The program should spawn a segfault *) bar() isn't static *) bar() isn't a not_so_smart_pointer method I think that I really miss something. Tested on gcc 4.0.1 with command-line: g++ -o test -Wall test.cpp Someone can explain me?
--"Low level programming is good for the programmer's soul" -- John Carmack
Advertisement
Quote:
*) operator-> return 0. The program should spawn a segfault

No, it shouldn't. Correct standard-compliant behavior for dereferencing a null pointer is undefined behavior. It doesn't have to segfault. It's very common however, for compilers to generate code that works as you've observed in this scenario. The reason is because the function in question does not use the "this" pointer (which is the null pointer in question here), so the compiler has no need to generate an attempt to read memory at that location, and no reason to segfault.
This most likely removes the class altogeter (common with templates), resulting in your code being simply:
int main(int argc, char* const argv[]){std::cout << "hi there\n";}
Quite like jpetrie already wrote. I could point out an additional resource, Segmentation fault, from Wikipedia that elaborates this somewhat and explains further what is happening. The reason this is undefined behaviour is that it is operating system dependent. It is the operating system that decides what it should do when a program tries to access memory that is not in the allocated are for it.

[EDIT: undeclard -> undefined - I must be too tired already...]

[Edited by - Naurava kulkuri on July 23, 2007 1:10:47 PM]
---Sudet ulvovat - karavaani kulkee
Quote:Original post by Antheus
This most likely removes the class altogeter (common with templates), resulting in your code being simply:
*** Source Snippet Removed ***


That is what I see when I check the compiler output:
LC0:	.ascii "hi there\12\0"	.text

and
call	___main	movl	$__ZSt4cout, (%esp)	movl	$LC0, %eax	movl	%eax, 4(%esp)


This is called empty base class optimisation. In essence this means that the internal representation of a class does not require any bits of memory at run time. This is the case typically for classes that contain only type members, nonvirtual function members, and static data members. Nonstatic data members, virtual functions, and virtual base classes, on the other hand, do require some memory at run time.

Anyway, if you try to print the size of that class with sizeof you probably get 1 as the answer. If your system imposes more strict aligment restrictions, it probably prints out 4. There is a great book regarding templates called C++ Templates: The Complete Guide by Nicolai M. Josuttis and David Vandevoorde.



---Sudet ulvovat - karavaani kulkee
Yes I know about the "undefined behaviour" but usually it's a segfault cause the program try to access to a block of memory that it can't access but it's not the point. On my system sizeof(not_so_smart_ptr<foo>) is 1.

The really thing I do not understand is that not_so_smart_ptr is a template and it cannot has the method "bar()". It's a method of the parameterized type "struct foo". Other than this operator-> do not returns a valid pointer.

I really do not understand.
--"Low level programming is good for the programmer's soul" -- John Carmack
Quote:Original post by zaerl
The really thing I do not understand is that not_so_smart_ptr is a template and it cannot has the method "bar()". It's a method of the parameterized type "struct foo". Other than this operator-> do not returns a valid pointer.

I really do not understand.


Maybe breaking things apart will help explain.

The original program:int main(int argc, char* const argv[]){   not_so_smart_ptr<foo> test;   test->bar();   return 0;}This is the same (equivilant):int main(int argc, char* const argv[]){   not_so_smart_ptr<foo> test;   foo* temp1 = test.operator->();   //note:  temp1 == 0   temp1->bar();   //note:  foo::bar() never dereferences "this" (aka temp1) internally, hence no crash.   //   if foo::bar...   //       ...were virtual   //       ...used a member variable   //       ...dynamic_cast<...>(this)ed   //       ...used any function that did one of the above   //       then it would probably crash.   return 0;}
Thanks man. It's a pretty weird behaviour...
--"Low level programming is good for the programmer's soul" -- John Carmack

This topic is closed to new replies.

Advertisement