Share via


C++: Weird looping mechanism

In the old days (sigh!!!) when I used to code in C++, I unfortunately had a friend with a knack of doing/finding weird ways of programing. One day he asked me the following question

How do you write a program in C++ which does not have any looping construct and yet it can print a string n-times, even though the string is present only once in the source file and its not called multiple (n) times.

The answer goes as

 #include <iostream>
using namespace std;
class MyClass
{
public:
    MyClass()
    {
        cout << "Hello World" << endl;
    }
};
int main(int argc, char* argv[])
{
    MyClass mc[10];
    return 0;
}

In C++, classes are not reference types and when you declare an array as above you actually create an initialized array of objects on the stack. So all the n-elements of the arrays is allocated and initialized by calling its default constructor. So for a n-element array the ctor is called n-times and you can print the string as many times using this.

Why would someone ever need to do something like this, beats me :). This became a sort of joke between us and when I joined MSFT and started working on .NET and sent him an email, saying that I was happy working in a language where you cannot do this kind of a thing.

When I first saw the bullet in the feature list of C# 3.0 that read "collection initializer" I was a bit scared. I thought maybe C# would support some construct in which the compiler will initialize all the elements of a collection/array by allocating the element with calls to default/some ctor. Fortunately thats not the case. For an example on object/collection initializer in C# 3.0 see here.

Comments

  • Anonymous
    April 17, 2006
    Funny stuff.. :D
  • Anonymous
    April 17, 2006
    "How do you write a program in C++ which does not have any looping construct or conditional constructs and yet it outputs the numbers 0 through 100, and the numbers 100 through 0."

    You can't imagine all the different ways people at work solved that one.
  • Anonymous
    April 17, 2006
    Anders, do share couple of them, here or at your blog. It'll be a nice read. Maybe I'd add how I solved it the first time when I heard the problem :) Or that I suggested memory optimization (??) by putting the writeline in finalizer as well so that you can do with half the number of objects. At that time I was not aware of the cost/complexity of finalization in .NET :)
  • Anonymous
    April 18, 2006
    First solution:

    #include <iostream>

    struct foo
    {
      foo()
      {
         std::cout << ++i << std::endl;
      }
      ~foo()
      {
         std::cout << i-- << std::endl;
      }
      static int i;
    };

    int foo::i = 0;

    int main()
    {
      foo f[100];
      // The following also works.
      // delete [] new foo[100];
    }
  • Anonymous
    April 18, 2006
    Second solution, using template specialization:

    #include <iostream>

    template <int i>
    void PrintNumbers()
    {
      std::cout << i << std::endl;
      PrintNumbers<i + 1>();
      std::cout << i << std::endl;
    }

    template <>
    void PrintNumbers<101>()
    {
    }

    int main()
    {
      PrintNumbers<1>();
    }
  • Anonymous
    April 18, 2006
    Third solution, using STL.

    #include <iostream>
    #include <vector>
    #include <numeric>
    #include <iterator>

    int main()
    {
      std::vector<int> w(100, 1);
      std::partial_sum(w.begin(), w.end(), w.begin());
      std::copy(w.begin(), w.end(), std::ostream_iterator<int>(std::cout, "n"));
      std::copy(w.rbegin(), w.rend(), std::ostream_iterator<int>(std::cout, "n"));
    }
  • Anonymous
    April 18, 2006
    Fourth solution, another STL solution.

    #include <iostream>
    #include <algorithm>
    #include <iterator>

    struct AddValue
    {
      AddValue() : miValue(1) {}
      int operator()() { return miValue++; }
      int miValue;
    };

    struct SubValue
    {
      SubValue() : miValue(100) {}
      int operator()() { return miValue--; }
      int miValue;
    };

    int main()
    {
        std::generate_n(std::ostream_iterator<int>(std::cout, "n"), 100, AddValue());
        std::generate_n(std::ostream_iterator<int>(std::cout, "n"), 100, SubValue());
    }
  • Anonymous
    April 18, 2006
    Fifth solution, made by the IT-guy. ;)

    #include <iostream>

    void Foo()
    {
      std::cout << "1" << std::endl;
      std::cout << "2" << std::endl;
      std::cout << "3" << std::endl;
      // ...snip...
      std::cout << "98" << std::endl;
      std::cout << "99" << std::endl;
      std::cout << "100" << std::endl;
      std::cout << "100" << std::endl;
      std::cout << "99" << std::endl;
      std::cout << "98" << std::endl;
      // ...snip...
      std::cout << "3" << std::endl;
      std::cout << "2" << std::endl;
      std::cout << "1" << std::endl;
    }
  • Anonymous
    April 18, 2006
    The template specialization is super cool. This is why C++ is so cool and most people who don't want to shoot themselves in the foot should avoid using it :)
  • Anonymous
    April 19, 2006
    I was going to comment on the template specialization, but I can't find my brain.  I think it squeezed out my ears and escaped in fear when I looked at that code.

    The leftover lizard brain recognizes that it could probably use a Perl script to generate that code.
  • Anonymous
    April 19, 2006
    The comment has been removed
  • Anonymous
    April 19, 2006
    The last example code, that is.