- Don’t use raw pointers as class members; that requires managing object life time and manually avoiding dangling pointers
- Use smart pointers instead of raw pointers
- Don’t use object references as class members as that makes objects of the class non-assignable (which means you cannot store said objects in standard C++ containers)
- Using raw pointers and object references to objects stored in standard C++ containers is problematic or impossible. Objects in containers can be relocated (addresses can change) rendering raw pointers and object references invalid.
- Best (only feasible?) option is to store
std::shared_ptr
of the dynamically allocated object in the container. std::shared_ptr
is reference countedstd::weak_ptr
is not- Use
std::make_shared
to create anstd::shared_ptr
to a dynamically created object instance or usestd::shared_ptr(new T())
- Only way to access members via
std::weak_ptr
is by callingstd::weak_ptr::lock
which returns anstd::shared_ptr
or 0 - To create an
std::weak_ptr
from the this pointer, the class must first derive fromstd::enable_shared_from_this
and then call theshared_from_this
function to get anstd::shared_ptr
pointing to the object. The object in question must be “owned” by anstd::shared_ptr
or else undefined behaviour results. Also,shared_from_this
must not be called from a constructor since the object is yet to be reference counted (i.e. object is not yet “owned” by anstd::shared_ptr
) - As a result of the previous point, it helps to ensure that objects can only be created via
std::shared_ptr
by using a public staticcreate
function (which returns objects “owned” by anstd::shared_ptr
) and making constructors private. Note that when constructors are made private, you can no longer use std::make_shared to create a shared pointer. You must usestd::shared_ptr(new T())
in this case.
Tag: programming
C++ Surprise 1 – const reference
“There are just two kinds of languages: the ones everybody complains about and the ones nobody uses.” — Bjarne
This doesn’t compile:
1 2 3 4 5 |
int main(){ int x = 10; double &y = x; // error: invalid initialization of reference of // type 'double&' from expression of type 'int' } |
This does:
1 2 3 4 |
int main(){ int x = 10; const double &y = x; } |
In the second case, y
is initialized by a temporary double
initialized from x
. Not sure what the rationale is but read up TCPPPL 5.5.
Here is where the inconsistency becomes very difficult to ignore:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include using std::cout; using std::endl; int main(){ int x = 10; const int &iy = x; const double &dy = x; x = 20; cout << x << endl; cout << iy << endl; cout << dy << endl; return 0; } |
If anyone knows the reasoning behind this, let me know.
“The procedure entry xxx could not be located in the dynamic link library msvcrt.dll.”
This is the error I was getting when trying to install an MSI I created for a C++/CLI project. Turns out that the MSI included glut.dll and opengll.dll. When building the MSI files, warnings are displayed to the effect that those two files should be excluded.
Click on the file name under “Application Folder” and set the “Exclude” property to false in the property grid. This fixes the problem.
Qt4 Development on Ubuntu – 1
Searching Google for [qt development ubuntu] took me to this article which details downloading and installing binaries from qt-project.org. I found from other sources that simply installing the qt4-dev-tools
package (using apt-get
or synaptic
) is the easier option.
“Getting Started Programming with Qt” is a very good introduction to programming Qt. One quirk I came across in the code in that article is the qApp pointer. What looked like a typo turned out to be a global pointer to the QApplication
instance (similar to MFC’s CWinApp
instance).
I did not like the “private slots:” syntax. That is not standard C++. I think I liked almost everything else about Qt that I have seen so far.
Further reading:
cadview – 2: Running on Windows
Here are two examples of cadview clients running on Windows. The first is simply the earlier gladeui sample built on Windows using MSVC. Headers and libraries for GTK+ (http://www.gtk.org/download/win32.php) need to be installed. A VC++ project [1] was created to refer to the gladeui source files. The project is located at /src/msvc/gladeui. No significant changes were made to the gladeui source.
The second example is called winui and talks directly to the Windows API and GDI+. When handling paint events we require an object using which to perform graphics output. In the GTK+ case, I could simply create the cairo_t
object within the handler. In case of the Windows API, the output must be performed via an HDC
which is passed as a parameter with the WM_PAINT
event. In order to accommodate this, cad_gui_view::paint
was modified to take a cad_gui_view::graphics_type&
as a parameter. winui is located at /src/msvc/winui in the repo.
- ^ I had to fall back on a handcrafted MSVC build since CMake failed to find GTK+ and Boost on Windows. The MSVC solution can be found at /src/msvc/msvc.sln within the repository.
boost::regex
(http://www.boostpro.com/download/) headers and libraries need to be installed for both examples.
cadview – 1: Introduction
cadview is a C++ library which provides a cross-platform GUI widget for 2D drafting. Presently, the following features are supported:
- Zoom/Pan
- Polyline tool
- Entering x,y co-ordinates via mouse selection or text entry
Installation
No installation packages are available yet and the executable has to be built from source. cadview depends on the following tools and libraries:
On a Fedora 16/17 machine, you can install the above dependencies as follows:
1 |
$ sudo yum install mercurial gcc-c++ gtk2-devel boost-devel cmake |
Obtain the source using Mercurial as follows:
1 |
$ hg clone https://code.google.com/p/cadview |
This should place the source in a directory named cadview
in your current directory. To build the binaries:
1 2 3 4 5 |
$ cd cadview $ mkdir build $ cd build $ cmake ../src $ make |
gladeui is a test application that uses cadview on GTK+. You can run gladeui as follows:
1 2 |
$ cd gladeui $ ./gladeui |
Select File>Polyline to activate the polyline tool. The UI controls are as follows:
- Click to add a point to the polyline
- A point can also be added by entering an x,y co-ordinate pair in the textbox and hitting <Enter>
- Pan by holding down the middle mouse button
- Zoom by turning the mouse wheel
- Right-click or hit <Esc> to end the polyline
Design Overview
The visible area of the widget – the view – is represented by the cad_gui_view
class. cad_gui_view
does not interact directly with the underlying GUI but instead depends on a pair of adaptor classes for GUI facilities.
The first adaptor class is the template parameter U
of cad_gui_view
and provides facilities like getting the position of the mouse cursor (get_mouse_position
) and invalidating the view (invalidate
). The second adaptor class is the U::graphics_type
type. This type provides facilities to draw on screen (draw_polyline
, move_to
, line_to
) and converting between screen and world co-ordinates (device_to_user
).
The cad_gtk_adaptor
is an implementation of the first adaptor class (the U
parameter) using GTK+. cad_cairo_graphics
implements the U::graphics_type
using cairo. In a similar way, we can create adaptors for other GUI platforms (e.g. cad_windows_adaptor
to wrap around Windows API and cad_windows_graphics
to talk to an HDC).
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 38 39 40 41 42 |
template U& gui; public: typedef typename U::graphics_type graphics_type; // ... void paint(); void mouse_move(int x, int y); void mouse_down(Mouse_button button, int x, int y); void mouse_up(Mouse_button button, int x, int y); void device_to_user(point_2d }; template GtkWidget *widget; public: typedef cad_cairo_graphics // ... void create_graphics(graphics_type *graphics); void get_mouse_position(int *x, int *y); GtkWidget* get_widget(); void invalidate(); }; template cairo_t *cr; public: // ... void move_to(const T x, const T y); void line_to(const T x, const T y); void draw_polyline(const polyline_2d }; |
MySQL calls via PDO fail silently
By default any error that occurs on a MySQL call via PDO fails quietly. The caller must inspect $pdo->errorCode()
to see if the call succeeded/failed. This behaviour can be changed by setting the ATTR_ERRMODE attribute either while constructing the PDO object or after construction via setAttribute.
1 2 |
$options = array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION); $pdo = new PDO($dsn, $username, $password, $options); |
Test if a Point lies inside a Polygon (from CGA FAQ)
The CGA FAQ describes an algorithm to test if a point lies within a polygon. Roughly speaking, you start from the point and travel north. If you cross an odd number of sides, it means that you were within the polygon when you started and vice versa.
The details of the solution can be found in the CGA FAQ linked above. A C++ implementation can be found here: http://code.google.com/p/curve-project/source/browse/trunk/lab/cgafaq/cgafaq.h The function cgafaq::point_in_polygon
takes a point and a polygon and returns whether or not the point lies inside the polygon. This is a direct translation of the code from the FAQ.
Disclaimer: This post and the code provided are not endorsed by any of the contributors to the CGA FAQ.
Orientation of Polygons (from CGA FAQ)
The orientation of a polygon tells us if the vertices are ordered clockwise or counter-clockwise as we move along the perimeter. This is determined by calculating the polygon’s signed area which is positive for counter-clockwise orientation and negative for clockwise orientation. A quicker algorithm is to determine the signed area of the triangle formed by the lowest right most vertex and it’s immediate neighbors.
The details of the solution can be found in the CGA FAQ linked above. A C++ implementation can be found here: http://code.google.com/p/curve-project/source/browse/trunk/lab/cgafaq/cgafaq.h The function cgafaq::orientation
has two overloads. The first computes orientation for three vertices and the second calculates the orientation of a polygon.
Disclaimer: This post and the code provided are not endorsed by any of the contributors to the CGA FAQ.
Distance of a Point from a Line (from CGA FAQ)
The distance of a point from a line is the length of a perpendicular drawn from the point to the line. Here are the possibilities:
- Perpendicular meets on the line segment
- Perpendicular meets on a forward/backward extension of the line segment
The details of the solution can be found in the CGA FAQ linked above. A C++ implementation can be found here: http://code.google.com/p/curve-project/source/browse/trunk/lab/cgafaq/cgafaq.h The function cgafaq::distance_from_line
takes the start and end points of the line and the point from which distance is to be calculated. r and s are output parameters calculated as described in the FAQ.
Note that if distance is not important and only a perpendicular needs to be generated then there is a simpler way to construct one.
Disclaimer: This post and the code provided are not endorsed by any of the contributors to the CGA FAQ.