Daily Archives: 7 April 2017


C++: “undefined reference to” templated class function 6

In case you have a project where you use a templated class that is split in its own header (.h) and source (.cpp) files, if you compile the class, into an object file (.o), separately from the code that uses it, you will get the undefined reference to error at linking.

Lets assume we have Stack.cpp and Stack.h which define a templated stack using vectors. And main.cpp that uses this class after including Stack.h.

If you try to compile these files as mentioned above, one by one, later you will get a linking error saying undefined reference to for the methods of the class.

The code in the template is not sufficient to instruct the compiler to produce the methods that are needed by main.cpp (e.g. Stack<int>::push(...) and Stack<string>::push(...)) as the compiler does not know, while compiling Stack.cpp by itself, the data types it should provide support for.

The reason it allows you to compile these incomplete objects is the following:

  • main.cpp: the compiler will implicitly instantiate the template classes Stack<int> and Stack<string> because those particular instantiations are requested in main.cpp. Since the implementations of those member functions are not in main.cpp, nor in any header file included in main.cpp (particularly Stack.h), the compiler will not include complete versions of those functions in main.o and it will expect to find them in another object during linking.
  • Stack.cpp: the compiler won’t compile the instantiations of Stack<int> and Stack<string> neither as there are no implicit or explicit instantiations of them in Stack.cpp nor Stack.h.

So in the end, neither of the .o files contain the actual implementations of Stack<int> and Stack<string> and the linking fails.

Solutions

Solution 1 : Explicitly instantiate the template

At the end of Stack.cpp, you can explicitly instantiate all needed templates.
In our example we would add:


template class Stack<int>;
template class Stack<std::string>;

This will ensure that, when the compiler is compiling Stack.cpp that it will explicitly compile all the code needed for the Stack<int> and Stack<std::string> classes.

Using this method, you should ensure that all the of the implementation is placed into one .cpp file and that the explicit instantation is placed after the definition of all the functions (for example, at the end of the file).

A problem with this method is that it forces you to update the Stack.cpp file each time you want to add support for a new data type (or remove one).

Solution 2 : Move the implementation code into the header file

Move all the source code of Stack.cpp to Stack.h, and then delete Stack.cpp. Using this method you do not need to manually instantiate all possible data types that are needed and thus you do not need to modify code of the class. As a side-effect, if you use the header file in many other source files, it will compile the functions of the header file in each source. This can make compilation slower but it will not create any compilation/linking problems, as the linker will ignore the duplicate implementations.

Solution 3 : Move the implementation code into a new header file and include it in the original header file

Rename Stack.cpp to Stack_impl.h, and then include Stack_impl.h from Stack.h to keep the implementation in a separate file from the declaration. This method will behave exactly like Solution 2.


How does the expression, “*pointer++” evaluate?

*pointer++ will increment the position of the pointer first but it will return the value that was pointed before the position of the pointer changed.

*pointer++ is equivalent to *(pointer++). This happens because the postfix ++ and -- operators have higher precedence than the indirection (dereference).
You can read more about the precedence order at this very helpful article at Wikipedia: https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence

To increment the value pointed to by pointer, use (*pointer)++.

To increment the position of the pointer and return the value that is pointed after the position of the pointer changed use *++pointer.

Examples

The following example will increment the position of the pointer but return the value that was originally pointed.
By the end of the following block, pointer will point to position 1 and the value variable will have the value 11.


const unsigned int values[] = {11, 12, 14, 18};
const unsigned int *pointer = values;
const unsigned int value = *pointer++;

The following example will increment the position of the pointer and return the value that the new position is pointing to.
By the end of the following block, pointer will point to position 1 and the value variable will have the value 12.


const unsigned int values[] = {11, 12, 14, 18};
const unsigned int *pointer = values;
const unsigned int value = *++pointer;


How to Start/Stop or Enable/Disable firewalld on Fedora 25

firewalld (Dynamic Firewall Manager) tool provides a dynamically managed firewall. The tool enables network/firewall zones to define the trust level of network connections and/or interfaces. It has support both for IPv4 and IPv6 firewall settings. Also, it supports Ethernet bridges and allow you to separate between runtime and permanent configuration options. Finally, it supports an interface for services or applications to add firewall rules directly.

Disable firewalld

To disable firewalld, execute the following command as root or using sudo:

systemctl disable firewalld;

Enable firewalld

To enable firewalld, execute the following command as root or using sudo:

systemctl enable firewalld;

Stop firewalld

To stop (or deactivate) firewalld,execute the following command as root or using sudo:

systemctl stop firewalld;

Start firewalld

To start (or activate) firewalld, execute the following command as root or using sudo:

systemctl start firewalld;

Status of firewalld

To check the status of firewalld, execute the following command as root or using sudo:

systemctl status firewalld;

CONCEPTS

systemd provides a dependency system between various entities called “units” of 12 different types. Units encapsulate various objects that are relevant for system boot-up and maintenance. The majority of units are configured in unit configuration files, whose syntax and basic set of options is described in systemd.unit(5), however some are created automatically from other configuration, dynamically from system state or programmatically at runtime. Units may be “active” (meaning started, bound, plugged in, …, depending on the unit type, see below), or “inactive” (meaning stopped, unbound, unplugged, …), as well as in the process of being activated or deactivated, i.e. between the two states (these states are called “activating”, “deactivating”). A special “failed” state is available as well, which is very similar to “inactive” and is entered when the service failed in some way (process returned error code on exit, or crashed, or an operation timed out). If this state is entered, the cause will be logged, for later reference. Note that the various unit types may have a number of additional substates, which are mapped to the five generalized unit states described here.
— From man systemd

The above, in a nutshell:

  • enabled is a service that is configured to start when the system boots
  • disabled is a service that is configured to not start when the system boots
  • active is a service that is currently running
  • inactive is a service that is currently stopped and may be disabled, but it can be started and become active