Effective C++ item 18: Make interfaces easy to use correctly and hard to use incorrectly.

A good API will not only provide easy to use interfaces, but also provide hard to mis-used interfaces. Usually, the later point is the fundamental of the earlier one. Consider you want to write a date class, there are thousands of ways to write it. Let’s see two simple examples:

1
2
3
4
5
6
7
8
9
10
11
12
// A date class which is easy to use but also easy to use wrong.
class Date
{
public:
Date(int month, int day, int year);
...
};

// Both are ok, but some european programmer may use it wrong.
// Because european time is dd/mm/yyyy instead of mm/dd/yyyy.
Date d(3, 4, 2000);
Date d(4, 3, 2000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// Class date which is easy to use and not easy to use wrong.
class Date
{
public:
struct Day
{
explicit Day(int d):val(d){}
int val;
};
struct Month
{
explicit Month(int m):val(m){}
int val;
};
struct Year
{
explicit Year(int y):val(y){}
int val;
};

Date(const Month& m, const Day& d, const Year& y)
: m_month(m)
, m_day(d)
, m_year(y) {};
~Date(){};

private:
Month m_month;
Day m_day;
Year m_year;
};

Date d1(Date::Month(3), Date::Day(3), Date::Year(2000)); // Ok

// Compilation error!
// no matching function for call to 'Date::Date(Date::Day, Date::Month, Date::Year)'
Date d2(Date::Day(3), Date::Month(3), Date::Year(2000));

Let’s see another example, suppose your interface returns a dynamically allocated resource which need to be released after all. The chances are programmers might forget to release it causing leaks. Returning a smart pointer maybe a good idea.

1
2
// Not easy to use interface, client has to remember to release the resource
Investment* createInvestment();
1
2
3
4
5
6
7
8
9
10
11
// Better interface returning smart pointer. Resource is released automatically
// Here releaseInvestment is deleter of shared_ptr to release resources
sdt::tr1::shared_ptr<Investment> createInvestment()
{
new Investment iv;
std::tr1::shared_ptr<Investment> retVal(iv, releaseInvestment);

...

return retVal
}

Reference:
“Effective C++” Third Edition by Scott Meyers.