From Schmid.wiki
Jump to: navigation, search

Common Pitfalls

C++ declarations:

int x;              // declare x of type int
int x(7);           // declare x of type int and initialize to 7
int x();            // declare FUNCTION x(void) => int
int *x = new int(); // declare x of type int *

C++ weird scope resolution:

class foo {};

class bar {
    int foo(); // a member function named like a class
    //foo f; // syntax error : missing ';' before identifier 'f'
    ::foo f; // specify scope to avoid error
};

C++ pointer containers:

boost::ptr_map does not support abstract classes.

boost::ptr_map can be emulated using a combination of
std::map and boost::ptr_list (or another non-associative container).

Elements in boost::ptr_list cannot be removed or found by their address. See the Boost Pointer Container Library page for a workaround.

C++ algorithms:

  • the remove algorithm does not remove anything, it moves 'unremoved' elements to the front of a container.
  • erase really removes elements
  • list::remove also erases the elements
  • erase means

Math

Random

C++:

#include <random>
// rand() is only 15 bit!! Don't use it
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, SIZE-1);
int rand = dis(gen);

Strings

Automatic String Conversion

C#:

class MyClass {
    public string ToString() {
        return "MyClass instance";
    }
}
...
MyClass myClass = new MyClass();
System.Console.WriteLine("myClass: " + myClass.ToString());

C++:

#include <ostream>
namespace Some_namespace {
    using std::ostream;
    class My_class {
        friend ostream & operator << (ostream &, const My_class &);
    };
}
// Drop overloaded ostream operator in global namespace
ostream & operator <<(ostream & os,
  const Some_namespace::My_class &my_class) {
    return os << "My_class instance";
}
using namespace std;
int main() {
    Some_namespace::My_class my_class;
    cout << "my_class: " << my_class << endl;
}

Ruby:

class My_class
    def to_s() "My_class instance" end
end
my_class = My_class.new
puts "my_class: " + my_class

Regular Expressions

C#:

using System.Collections.Generic;
using System.Text.RegularExpressions;

class RegexTest {
    static void Main() {
	List<string> words = new List<string>() {
            "HEJ", "Hello", "yo" };
	Regex acceptedWordRegex = new Regex("he.*", RegexOptions.IgnoreCase);
	Regex wordSubstitutionRegex =
            new Regex("(^.)e(.*)", RegexOptions.IgnoreCase);
	foreach(string word in words) {
	    if(acceptedWordRegex.IsMatch(word)) {
		string s = wordSubstitutionRegex.Replace(
                    word, "$2e$1");
		System.Console.WriteLine(s);
	    }
	}
    }
}

C++:

#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <iostream>

using namespace std;

int main() {
    char *words[] = { "HEJ", "Hello", "yo" };
    boost::regex accepted_word_regex("he.*", boost::regex::icase);
    boost::regex word_substitution_regex("(^.)e(.*)", boost::regex::icase);

    BOOST_FOREACH(char *word, words) {
	if(regex_match(word, accepted_word_regex)) {
	    string s = regex_replace(string(word),
		           word_substitution_regex, string("\\2e\\1"),
			   boost::match_default);
	    cout << s << endl;
	}
    }
}

Ruby:

words = [ "HEJ", "Hello", "yo" ]
words.each { |word|
    if word =~ /he.*/i then
	puts word.gsub(/(^.)e(.*)/i,'\2e\1')
    end
}

System

Directory Iteration

C++

#include <filesystem>
#include <sstream> // just used for string output

using namespace std::tr2::sys;

const path my_path("d:/some/path"); // note that forward slashes work in Windows
assert( exists( my_path ) );
directory_iterator end_itr; // default construction yields past-the-end
for (directory_iterator itr(my_path); itr != end_itr; ++itr) {
    if (itr->path().extension() == ".txt") {
	std::cout << " - " << itr->path();
    }
}

C++17:

#include <filesystem>

using std::experimental::filesystem::path;
using std::experimental::filesystem::directory_iterator;

const path my_path("d:/some/path"); // note that forward slashes work in Windows
assert( exists( my_path ) );
directory_iterator end_itr; // default construction yields past-the-end

for (auto &entry : directory_iterator(my_path)) {
    if (entry.path().extension() == ".txt") {
	std::cout << " - " << entry.path();
        printf("file: %s", entry.path().filename().u8string().c_str());
    }
}

Writing Files

C#:

using System.IO;
// ...
Directory.CreateDirectory("/tmp/filetest");
using (StreamWriter sw = new StreamWriter("/tmp/filetest/testfile")) {
    sw.WriteLine("yo");
}
if(File.Exists("/tmp/filetest/testfile"))
    Console.WriteLine("we have created a file");

C++:

// link with boost_filesystem and boost_system
#include "boost/filesystem.hpp"
#include <iostream>
#include <fstream>

using namespace boost::filesystem;
using namespace std;

int main() {
    create_directory("/tmp/filetest");
    ofstream file("/tmp/filetest/testfile");
    file << "yo" << endl;
    file.close();
    if(exists("/tmp/filetest/testfile"))
	cout << "we have created a file" << endl;
}

Ruby:

require 'fileutils'
include FileUtils
mkdir_p "/tmp/filetest"
IO.popen("/tmp/filetest/testfile") { |f| f.puts "yo" }
if File.exists?("/tmp/filetest/testfile") then
    puts "we have created a file"
end

Time

Sleeping For 1.5 Seconds

C++:

#include <boost/thread.hpp>
#include <boost/date_time.hpp>
using namespace boost;
this_thread::sleep(posix_time::seconds(1.5f)); 

Record Time

C++:

#include <boost/timer.hpp>
boost::timer timer;
// Time elapsed since construction.
double elapsed_time__s = timer.elapsed();

Data Structures

Static Array

C#:

int [] myArray = new int [size];
int [] myArray2 = new int [] {1, 2, 3};
myArray[7] = 60;
int x = myArray[7];

C++ with value semantics:

int my_array[size];
int my_array2[] = {1, 2, 3};
my_array[7] = 60;
int x = my_array[7];

C++ with pointer semantics:

int * my_array;
my_array = new int [size];
int x = my_array[7];
delete [] my_array;

Dynamic Array

C#:

using System.Collections.Generic;
List<int> numbers(1);
numbers.Add(10);
numbers.Add(23); // reallocate

C++ with value semantics:

#include <vector>
using std::vector;
vector<int> numbers(1);
numbers.push_back(10);
numbers[1] = 23; // reallocate

C++ with pointer semantics:

#include <boost/ptr_container/ptr_vector.hpp>
using boost::ptr_vector;
struct Thing {
    Thing(int x) : x_(x) {}
    int x_;
};
ptr_vector<Thing> things(1);
things.push_back(new Thing(10));
things[1] = new Thing(23); // reallocate

Ruby:

numbers = Array.new(1)
numbers.push(10)
numbers[1] = 23

Linked List

C++:

#include <list>
#include <algorithm>
using namespace std;
list<int> l;
l.push_back(4);
l.push_back(9);
l.remove(4); // list::remove both removes and erases

// Filter based upon arbitrary predicate. Note that due to a
// weirdness in C++98, you cannot use local classes as predicates.
struct Larger_than {
    Larger_than(int value) : value(value) {}
    inline bool operator() (int value_to_check) const {
        return value_to_check > value;
    }
    int value;
};
l.remove_if(Larger_than(5)); // both removes and erases

struct Is_even {
    inline bool operator() (int value_to_check) const {
        return value_to_check % 2 == 0;
    }
};
l.remove_if(Is_even());

// search for value
list<int>::iterator i = find(l.begin(), l.end(), 7);
if(i == l.end()) {
    // couldn't find 7
}
else {
    // found it
}

Associative Array

C#:

using System.Collections.Generic;
// ...
Dictionary<string, Thing> name2thing = new Dictionary<string, Thing>();
name2thing["thing 1"] = new Thing("hey");
name2thing["thing 2"] = new Thing("there");
name2thing.Remove("thing 1");
if(name2thing.ContainsKey("thing 1") { ... }
foreach(string s in name2thing.Keys) {
    System.Console.WriteLine(name2thing[s].Name);
}

C++:

#include <map>
#include <string>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;
// ...
typedef map<string, Thing *> Name_2_thing;
typedef Name_2_thing::iterator Name_2_thing_iterator;
Name_2_thing name_2_thing;
name_2_thing["thing 1"] = new Thing("hey");
name_2_thing["thing 2"] = new Thing("there");
name_2_thing.erase("thing 1");

// find member
Name_2_thing_iterator i = name_2_thing.find("thing 1");
if(i == name_2_thing.end()) {
    // handle error: no such key
}
else {
    Thing * thing = i->second;
}

// delete member
Name_2_thing_iterator i = name_2_thing.find("thing 1");
if(i == name_2_thing.end()) {
    // handle error: no such key
}
else {
    name_2_thing.erase(i);
}



BOOST_FOREACH(Name_2_thing::value_type &i, name_2_thing) {
    cout << i.second->get_name() << endl;
}

Ruby:

// ...
name_2_thing = {}
name_2_thing["thing 1"] = Thing.new("hey")
name_2_thing["thing 2"] = Thing.new("there")
name_2_thing.delete("thing 1")
if name_2_thing.has_key?("thing 1") then ... end
name_2_thing.each do |name,thing|
    puts thing.name
end

Classes

Class Definition

C#:

namespace MyNamespace {
    class MyClass {
        int someValue;

        MyClass(int someValue) {
            this.someValue = someValue;
        }
        ~MyClass() {
            System.Console.WriteLine("destroyed.");
        }
        public int SomeValue {
            get { return someValue; }
            set { someValue = value; }
        }
        private void something() {}
        static void Main() {
            MyNamespace.MyClass mc = new MyNamespace.MyClass(7);
            System.Console.WriteLine(mc.SomeValue);
        }   
    }   
}   

C++:

#include <iostream>
namespace My_namespace {
    class My_class {
    public:
        My_class(int some_value) : some_value(some_value) {}
        ~My_class() {
            std::cout << "destroyed." << std::endl;
        }
        int some_value() { return some_value; }
        void some_value(const int &new_value) { some_value = new_value; }
    private:
        void something() {}
        int some_value;
    }
};
int main() {
    My_namespace::My_class mc = new My_namespace::My_class();
    std::cout << mc->my_method() << std::endl;
    delete mc;
}

Ruby:

module My_namespace
    class My_class
        attr_accessor :some_value
        def initialize(some_value)
            @some_value = some_value
        end
        def release_resources() # not destructor
            puts "destroyed."
        end
        def something() end
    end
end

mc = My_namespace::My_class.new(7)
puts mc.some_value
mc.release_resources() # manually calling cleanup method

Virtual Methods

C#:

class Something

Common Design Patterns

Factory Method

C++:

Returning a new Thing could just as well be done using a raw pointer. The caller could then store the pointer in a smart pointer or deallocate using delete. However, it is not explicit in the interface that the caller has to handle resource deallocation.

Using shared_ptr forces the caller to handle the memory correctly.

#include <memory>

using namespace std;

class Thing {
public:
    virtual ~Thing() { ... }

    // Named ctor.
    static shared_ptr<Thing> create_thing() {
        return shared_ptr<Thing>( new Thing(7) );
    }
    // Named ctor.
    static shared_ptr<Thing> create_special_thing() {
        return shared_ptr<Thing>( new Thing(60) );
    }
    // Virtual copy ctor.
    virtual shared_ptr<Thing> clone() {
        return shared_ptr<Thing>( new Thing(* this) );
    }
protected:
    // Private ctor accessed by factory methods.
    Thing(int x) : x_(x) { }
    // Private copy ctor accessed by clone.
    Thing( const Thing & other) : x_(other.x_) { }
private:
    int x_;
};

class Thingie : public Thing {
public:
    // Named ctor.
    static shared_ptr<Thingie> create_thingie() {
        return shared_ptr<Thingie>( new Thingie(70) );
    }
    // Virtual copy ctor.
    virtual shared_ptr<Thing> clone() {
	return shared_ptr<Thing>(new Thingie( * this ));
    }
private:
    // Private ctor accessed by factory methods.
    Thingie( int x ) : Thing(x) { }
    Thingie( const Thingie & other ) : Thing(other.x_) { }
};

int main() {
    shared_ptr<Thing> t0 = Thing::create_thing();
    shared_ptr<Thing> t1 = Thing::create_special_thing();
    shared_ptr<Thing> t2 = t1->clone();

    shared_ptr<Thing> t3 = Thingie::create_thing();
    shared_ptr<Thing> t4 = t3->clone();
}

Named Parameter

Ruby:

def do_stuff(unnamed_parameter, opts={})
    opts = {:named_parameter => 8, :other_named_parameter => true}.merge(opts) # default argument values

    if opts[:other_named_parameter] then
       ...
    else
       ...
    end
end

Observer

In C#, the Observer pattern is implemented as events.

C#:

class Subject {
    public delegate void SomeEventHandler(int someValue);
    public event SomeEventHandler SomeEvent;
    protected void doSomething() {
        if(SomeEvent != null) SomeEvent(7);
    }
}

class Observer {
    public Observer(Subject subject) {
        subject.SomeEvent += myHandler;
    }
    void myHandler(int someValue) {
        // ...
    }
}

In C++, boost::signal implements the Observer pattern.

C++:

#include <boost/signal.hpp>
#include <boost/bind.hpp>

class Subject {
public:
    boost::signal<void (int)> some_event;
protected:
    void do_something() {
        some_event(7);
    }
};
class Observer {
public:
    Observer(subject &subject) {
        subject.some_event.connect(boost::bind(& observer::my_handler, this, _1));
    }
    void my_handler(int some_value) {
        // ...
    }
};

In Ruby, observer.rb implements the Observer pattern.

require 'observer'

class Subject
    include Observable # mixin
    def do_something
        changed  # note that our state has changed
        notify_observers( 7 )
    end
end
class Observer
    class My_handler
        # the invoked method must be 'update'
        def update(some_value)
            # ...
        end
    end
    def initialize(subject)
        subject.add_observer(My_handler.new)
    end
end

References