jueves, 3 de octubre de 2013

Instalación, configuración y administración de Bacula 5.0 en CentOS

Introducción

Bacula es un software libre para la creación, ejecución y mantenimiento de salvas automáticas de archivos a través de la red en diversos medios de almacenamiento (disco duro, DVDs, memorias flash, cintas, etc.).

Instalación

Director

# Máquina donde va el servidor centralizado de bacula, 
# desde el cual se manejan los jobs.
yum install bacula-console bacula-director-sqlite

Paquetes alternativos del director:

  • bacula-director-sqlite
  • bacula-director-mysql
  • bacula-director-postgresql

Clientes

# Máquinas con el origen de los datos que se quieren salvar.
yum install bacula-client 

Almacenes

# Máquinas con el destino de los datos que se quieren salvar.
yum install bacula-storage-sqlite

Paquetes alternativos del storage:

  • bacula-storage-sqlite
  • bacula-storage-mysql
  • bacula-storage-postgresql

Configuración

El home de Bacula por defecto es /var/spool/bacula. Aquí se escriben los registros de operaciones, el catálogo de Bacula y los mensajes para el administrador.

El directorio base de la configuración es /etc/bacula/. Dentro, están los siguientes archivos:

  • bacula-dir.conf: Director (servidor de bacula)
  • bacula-fd.conf: File daemon (cliente, origen del backup)
  • bacula-sd.conf: Storage daemon (almacenamiento, destino del backup)
  • bconsole.conf: Consola de administración
  • query.sql: Querys del catálogo

Definiendo los recursos

Debemos tener en cuenta, primero que todo, las siguientes relaciones de dependencia entre recursos:

Job --> Client -> Catalog
    |-> FileSet
    |-> Pool 
    |-> Storage -> Device 
    |-> Schedule

Es aconsejable ir de lo más simple a lo más complejo, para armar las relaciones a medida que definimos los recursos.

1. Recurso FileSet: Define el conjunto de archivos de la máquina cliente que se incluyen y se excluyen a la hora de salvarse. Cuando es una carpeta, por defecto se incluyen todos los archivos y carpetas contenidos recursivamente. Ejemplo:

FileSet {
  Name = "face-blocks"
  Include {
    Options {
      signature = MD5
    }
    File = /var/lib/disklocal
  }

  Exclude {
    File = /var/lib/disklocal/lost+found
  }
}

2. Recurso Device: Por lo general, sirven para definir el camino en el sistema de archivos de la partición en el que se monta el dispositivo en la máquina almacén. En este dispositivo serán guardados los volúmenes (la salva) de manera binaria. No tiene que definirse en el director, pero sí debe estarlo en el almacén.

Device {
  Name = FileStorage
  Media Type = File
  Archive Device = /var/lib/backup
  LabelMedia = yes;                   # lets Bacula label unlabeled media
  Random Access = Yes;
  AutomaticMount = yes;               # when device opened, read it
  RemovableMedia = no;
  AlwaysOpen = no;
}

3. Recurso Catalog: Da conectividad con la base de datos que contiene los metadatos de nuestras salvas.

Catalog {
  Name = "MyCatalog"
  # Uncomment the following line if you want the dbi driver
  #dbdriver = "dbi:sqlite3"; dbaddress = 127.0.0.1; dbport =
  dbname = "bacula"; dbuser = "bacula"; dbpassword = ""
}

4. Recurso Pool: Permite utilizar uno o varios volúmenes (archivos o cintas) de almacenamiento, además de recilar y definir tamaño y cantidad de los volúmenes.

Pool {
  Name = File
  Pool Type = Backup
  Recycle = yes                # Bacula can automatically recycle Volumes
  AutoPrune = yes              # Prune expired volumes
  Volume Retention = 365 days  # one year
  Maximum Volume Bytes = 50G   # Limit Volume size to something reasonable
  Maximum Volumes = 100        # Limit number of Volumes in Pool
  Label Format = "vol-"        # Volume names: vol-0001, vol-0002, etc.
}

5. Recurso Schedule: Define los rangos de tiempo en los que se ejecutará una tarea.

# When to do the backups, full backup on first sunday of the month,
#  differential (i.e. incremental since full) every other sunday,
#  and incremental backups other days
Schedule {
  Name = "WeeklyCycle"
  Run = Full 1st sun at 23:05
  Run = Differential 2nd-5th sun at 23:05
  Run = Incremental mon-sat at 23:05
}

6. Recurso Client: Define los datos de la(s) máquina(s) fuente de los archivos en un FileSet a salvar.

Client {
  Name = bacula-fd
  Address = workers-arg2
  FDPort = 9102
  Catalog = MyCatalog
  Password = "datys1"        # password for FileDaemon
  File Retention = 30 days   
  Job Retention = 6 months   # six months
  AutoPrune = yes            # Prune expired Jobs/Files
}

7. Recurso Storage: Define los datos de la(s) máquina(s) destino de las salvas (donde están los dispositivos y se crean los volúmenes).

Storage {
  Name = face-storage
  Address = workers-arg2  # N.B. Use a fully qualified name here
  SDPort = 9103
  Password = "datys1"
  Device = face-device
  Media Type = File
}

8. Recurso Job: Define la tarea a realizar, teniendo en cuenta los recursos disponibles.

Job {
  Name = "backup-face-blocks"
  Type = Backup
  Level = Incremental # Do "Full" the first time, save changed after
  Client = bacula-fd
  FileSet = "face-blocks"
  Schedule = "DailyAt2315"
  Storage = face-storage
  Messages = Standard
  Pool = File
  Priority = 10   # Default, 1-99999... 1 (highest priority)
  Write Bootstrap = "/var/spool/bacula/%c.bsr"
}

Job {
  Name = "restore-face-blocks"
  Type = Restore
  Client = bacula-fd
  FileSet = "face-blocks"
  Storage = face-storage
  Pool = Default
  Messages = Standard
  Where = /tmp/face-restores  # Restore files at this location
}

Configuración del director (bacula-dir.conf)

  1. Generar un password aleatorio, para que dondequiera que aparezca password, actualizarlo.
  2. Si se desea mantener los recursos Client y los Storage por defecto, debe actualizarse Address al nombre de las máquinas clientes y almacenes, respectivamente.
  3. Se puede comentar los jobs de salvas del catálogo y los servicios de /usr/sbin.
  4. Para poder incluir otros archivos de configuración en el principal, creamos el directorio /etc/bacula/conf.d y adicionamos la siguiente línea al final de bacula-dir.conf:
    @|"sh -c 'for f in /etc/bacula/conf.d/*.conf; do echo @${f} ; done'"
  5. Correr los scripts de creación de las bases de datos ubicados en /usr/libexec/bacula/
    ./create_bacula_database 
    ./make_bacula_tables
  6. Definir nuestros archivos de configuración (terminados en .conf) en /etc/bacula/conf.d/. Los recursos que debemos definir, en caso de no existir son:
    • Job
    • Schedule
    • FileSet
    • Client
    • Catalog
    • Storage
    • Pool

Configuración del cliente (bacula-fd.conf)

  1. Usar el mismo password para el cliente definido en el director.

Configuración del almacén (bacula-sd.conf)

  1. Usar el mismo password para el storage definido en el director.
  2. Definir los dispositivos que se usarán para el almacén.
  3. Device {
      Name = face-device
      Media Type = File
      Archive Device = /var/lib/face-backup
      LabelMedia = yes;          # lets Bacula label unlabeled media
      Random Access = Yes;
      AutomaticMount = yes;      # when device opened, read it
      RemovableMedia = no;
      AlwaysOpen = no;
    }

Administración usando bconsole

Cuando instalamos el paquete bacula-console, podemos acceder a la administración de bacula a través de la aplicación bconsole, la cual debe estar configurada con los datos del director:

# /etc/bacula/bconsole.conf
Director {
  Name = bacula-dir
  DIRport = 9101
  address = localhost
  Password = "datys1"
}

Cuando ejecutamos esta consola podemos:

  1. Obtener ayuda de uso de la consola:
    help
  2. Ver el estado del director, clientes y almacenes:
    status all
    #status clients
    #status dir
    #status storage
    #status jobs
  3. Ejecutar jobs:
    run
  4. Cancelar jobs:
    cancel
  5. Restaurar archivos con jobs de restauración:
    restore
  6. Recargar la configuración del director:
    reload
  7. Nombrar un volumen a ser usado por el pool (necesario para iniciar un job si no se especifica Label Format en el recurso Pool):
    label

Referencias

  1. Kern Sibbald, Bacula Main Reference, Febrero 1, 2013.

lunes, 22 de octubre de 2012

Proyectos C/C++ de Eclipse a Autotools

La problemática de preparar proyectos de C/C++ para que se compilen en cualquier sistema compatible con el estándar POSIX, con las herramientas recomendadas por GNU conocidas como Autotools (autoconf, autoheader, automake, autoreconf, aclocal, libtoolize) es un procedimiento que puede llegar a ser exhaustivo, confuso y agobiante si no se cuenta con sugerencias prácticas y aspectos básicos sobre estas herramientas. Como Eclipse es uno de los ambientes de desarrollo más populares sobre todo en Linux, cuenta con un tipo de proyecto llamado GNU Autotools que da un buen nivel de integración con dichos programas e incluye un eficaz resaltado de sintaxis. Sin embargo, por defecto no permite ejecución o depuración, además de dar un cascarón vacío que carece de una información que bien pudiera deducirse automáticamente a partir de los proyectos originales de C/C++. Este artículo trata de cómo crear proyectos GNU Autotools en Eclipse que reutilicen los proyectos Executable, Shared library y Static library sin perder la posibilidad de depurarlos, ejecutarlos y mantenerlos. Supongamos que nuestro proyecto original se llame ProjectX.
  1. Creamos un directorio llamado gnu-ProjectX (puede ser otro nombre) al mismo nivel que nuestro proyecto en el espacio de trabajo de Eclipse.
  2. Movemos la carpeta del proyecto original hacia dentro gnu-ProjectX. Es importante aclarar que con un enlace simbólico FUNCIONAN ERRÓNEAMENTE las Autotools, por lo que desechamos esta variante.
  3. Desde Eclipse, eliminamos el proyecto ProjectX del workspace. ¡Es importante haber realizado el paso 2 antes de hacer esto!
  4. Creamos un nuevo proyecto de C/C++, en el wizard especificamos el nombre gnu-ProjectX (que coincide con el directorio que creamos anteriormente) como proyecto GNU Autotools, y según nuestro objetivo seleccionamos:
    • Hello World C++ Autotools Project, si lo que vamos a generar es un ejecutable.
    • Autotools Shared Library Project, si lo que vamos a generar es una biblioteca (estática o dinámica).
  5. Seguidamente, especificamos los datos de autor, copyright y demás. En el campo Source, entramos el nombre del proyecto original, ProjectX.
  6. Una vez creado el proyecto, podemos ver nuestro proyecto original dentro del nuevo proyecto. Podemos eliminar el archivo .cpp que se crea nuevo, pues no lo utilizaremos. ¡Cuidado no eliminar un archivo del proyecto original!
  7. Si lo que se ha creado es una biblioteca, deberá especificarse en el archivo configure.ac lo siguiente:
    AC_CONFIG_MACRO_DIR([m4])
    después del comando AC_PROG_LIBTOOL y en Makefile.am de la raíz del proyecto, especificar:
    ACLOCAL_AMFLAGS=-I m4
    para no recibir unas warnings cuando se ejecuten las Autotools.
  8. Verificamos en Makefile.am de la raíz que se incluya la línea:
    SUBDIRS=ProjectX
  9. con el nombre del directorio del proyecto original.
  10. La parte más complicada es modificar Makefile.am del directorio del proyecto ProjectX, por lo que brindaremos una secuencia especial de pasos:
    1. Si su código no está en la raíz del directorio del proyecto, deberá crear tantos Makefile.am como directorios anidados tenga, en los que debe especificar la variable SUBDIRS con los nombres de los directorios hijos necesarios. Luego, debe buscar la directiva AC_CONFIG_FILES en el archivo configure.ac y adicionar un Makefile por cada Makefile.am. Ejemplo:
      AC_CONFIG_FILES(Makefile 
                      ProjectX/Makefile 
                      ProjectX/src/Makefile)
    2. Buscamos una variable llamada bin_PROGRAMS y modificamos su valor al nombre del ejecutable que deseamos generar. Por ejemplo:
      bin_PROGRAMS=projectx.bin
      Si es una biblioteca, el prefijo deberá ser lib en vez de bin.
    3. Usando ese nombre, creamos (o modificamos si existe) una con el sufijo _SOURCES. Por ejemplo:
      projectx_bin_SOURCES=main.cpp tool.cpp write.cpp tools.h
      Para dar el valor de esta variable, podemos buscar el archivo subdir.mk que debe aparecer dentro de la carpeta Debug del proyecto ProjectX original. En este archivo debe aparecer una variable C_SRCS o CPP_SRCS en la que se enumeran los archivos de código fuente a compilar, por lo general uno por línea con \ al final. Copie y pegue el o los archivos aquí enumerados en en Makefile.am y asegúrese de que de ellos quede solo el nombre y extensión, es decir, que no tengan elementos de caminos relativos, como ../ . Al final del backslash que indica cambio de línea NO debe aparecer ningún otro caracter, incluido el espacio.
    4. Si tiene los archivos .c y/o .cpp distribuidos en varios directorios, entonces deberá poner los caminos relativos:
      projectx_bin_SOURCES=dir1/main.cpp dir2/tools.cpp
    5. Si usa alguna biblioteca, deberá definir una variable con el nombre del binario con sufijo _LDADD (o _LIBADD si es una biblioteca), por ejemplo:
      projectx_bin_LDADD=-ldaemon -lMyLib
      Para obtener estos valores, puede buscar el archivo objects.mk que debe aparecer dentro de la carpeta Debug del proyecto ProjectX. En este archivo debe aparecer una variable LIBS cuyo valor puede usar.
  11. Ahora debemos correr las Autotools en orden:
    • aclocal
    • autoheader (solo si se usa la directiva AC_CONFIG_HEADERS en configure.ac)
    • autoconf
    • libtoolize (solo para bibliotecas)
    • automake --add-missing
    • autoreconf (para reconfigurarlo todo, por si acaso)
    Esto se puede hacer desde la línea de comandos en el directorio del proyecto gnu-ProjectX o desde Eclipse, seleccionando el proyecto en el Project Explorer, y luego ir al menú Project / Invoke Autotools. Estas herramientas deben estar instaladas, desde luego. En Debian/Ubuntu por ejemplo, los paquetes autoconf, automake y libtool tienen todo lo necesario. En caso de que Eclipse emita un mensaje de error como:
    sh autoconf
    
    sh: 0: Can't open autoconf
    abra las propiedades del proyecto, busque la sección Autotools / General y en la pestaña Tool Settings especifique cada herramienta con su camino absoluto, por ejemplo: /usr/bin/autoconf. Consulte los manuales de las herramientas automake y autoconf para más información.
  12. Una vez corridas todas las Autotools sin error, deberán haberse creado muchos archivos nuevos, como son: aclocal.m4 config.guess config.status config.sub configure INSTALL install-sh Makefile Makefile.in missing.
  13. Supongamos que en nuestro código usamos encabezados (headers) o bibliotecas no estándares, es decir, que no aparecen por defecto bajo el directorio /usr/include o /lib, /usr/lib que son incluidos por defecto a la hora de compilar. Si es así, podemos optar por la alternativa de definir (o aumentar) las variables de entorno:
    • CPATH para los headers, caminos absolutos separados por dos puntos (:).
    • LIBRARY_PATH para las bibliotecas, caminos absolutos separados por dos puntos (:).
  14. Desde la línea de comandos, en el directorio gnu-ProjectX ejecute:
    ./configure
    
    make
    Chequee si se produjo o no algún error. En caso afirmativo, deberá comprender el mensaje de error para poder darle solución. Deberá determinar si el fallo fue en los archivos del configuración de Autotools, o faltan prerrequisitos, variables de entorno sin definición o incompletas, o errores de compilación. Según sea el caso, consulte los manuales o la Internet.
  15. Si todo terminó felizmente, pruebe a instalar (correr desde una cuenta con permisos de administración):
    make install
    Chequee el o los binarios en /usr/local/bin (por defecto) y las bibliotecas en /usr/local/lib.
  16. Si la instalación se realizó con éxito, trate de probar lo instalado. Una vez comprobado, puede ejecutar el comando:
    make dist
    para crear un paquete .tar.gz, el cual puede distribuir.
  17. Solo falta que volvamos a tener la posibilidad de ejecutar y depurar el proyecto. Esto es sencillo: desde el Project Explorer en Eclipse, haga clic derecho en algún lugar, debe aparecer la opción Import..., busque en General / Existing projects into Worspace, busque la carpeta de ProjectX dentro de gnu-ProjectX y haga clic en el botón Finish y listo.
En conclusión, ya estamos listos para empaquetar, desplegar y compilar nuestro código de C o C++, sin perder la posibilidad de mantenerlo actualizado, depurarlo y probarlo en Eclipse.

jueves, 16 de agosto de 2012

C++0x + Debian 6

¿Es posible aprovechar algún nuevo recurso de C++, discutido e incluido en el nuevo estándar conocido inicialmente como C++0x y luego rebautizado como C++11, usando gcc/g++ 4.4.5, que es la predeterminada en Debian 6? Responder esta pregunta es el objetivo de este artículo.

Primero, la respuesta corta: sí, es posible.

Luego, la respuesta larga. En este sitio, podrán encontrar las características implementadas en la versión 4.4 del compilador GNU gcc. Pero ver sólo la página no dice mucho, por lo que nos entretuvimos en identificar, comprender y verificar las más atractivas.

  1. Variables con declaración automática de tipo (auto).
  2. Inicialización de colecciones.
  3. enum ahora fuertemente tipado.
  4. Permitidos varios caracteres > seguidos.
  5. Referencias a rvalue.
  6. Manejo de funciones predeterminadas.

Para ello construimos un proyecto de pruebas unitarias usando el framework lite UnitTest++. La compilación con g++ debe realizarse con la opción -std=c++0x para habilitar las nuevas extensiones del lenguaje.

Variables con declaración automática de tipo

Cuando necesitamos declarar una variable, ya sea en C o C++ es necesario especificar su tipo y de manera opcional su valor inicial. Una variable declarada como auto deduce su tipo a partir del tipo de la expresión con que se inicializa. Veamos la prueba:

#include <UnitTest++.h>
#include <string>
#include <iostream>
#include <vector>

using namespace std;

struct A
{
 int p;
};

TEST(Use_of_auto_type_supported)
{
 auto i = 5;
 int a = i + 5;
 CHECK_EQUAL(10, a);
 
 auto s = string("a");
 string b = s + "b";
 CHECK_EQUAL(0, b.compare("ab"));
 
 auto t = new A;
 t->p = 5;
 A sta;
 sta = *t;
 CHECK_EQUAL(5, sta.p);
 
 auto d = 5.6;
 double dd = 4.4 + d;
 CHECK_CLOSE(10, dd, 0.01);
 
 auto c = 'a';
 char cc[1];
 cc[0] = c;
 CHECK_EQUAL('a', cc[0]);
}

Como se puede ver, la variable i es de tipo int, s es string, t es un apuntador a la estructura A, d es un double y c un char. Cada tipo ha sido deducido a partir de la expresión de inicialización. Sin embargo, una expresión como la siguiente:

 auto p = null;

es inválida pues null no es expresión que defina un tipo particular. Con este recurso resolvemos los tediosos bloques como el siguiente:

for (vector<a_big_name_type>::const_iterator iter = collection.begin();
   iter != biometricTypes.end();
   ++iter)
{
 ...
}

Ahora podemos escribir:

for (auto iter = collection.begin(); 
   iter != biometricTypes.end();
   ++iter)
{
 ...
}

Para más información, ver este documento.

Inicialización de colecciones

Desde C# 3.0 se tiene algo como esto. Pues ya en C++ es perfectamente posible:

TEST(Init_lists)
{
 vector<int> a {1, 2, 3, 4 ,5};
 vector<string> s {"1", "2", "3"};
 CHECK_EQUAL(3, a[2]);
 CHECK_EQUAL(0, s[1].compare("2"));
}

El vector a contiene 5 números, desde el 1 al 5, mientras que s tres cadenas. Para más información, ver este link.

enum ahora fuertemente tipado

Desde tiempos immemoriales, los nombres de los campos de dos enumeraciones no podían coincidir. Es decir, que esto era ilegal:

 enum A { A1, A2 };
 enum B { A1, B1 }; // Ilegal, nombre A1 repetido.

Por lo general se resolvía el problema poniéndoles prefijos a los nombres de los campos, y así no "colisionaran" unos con otros. Pero dicha técnica no era otra cosa que un disimulado parche. Para resolver problemas de nombres, asignación/conversión directa a enteros, tamaño en memoria de los enum y otros, se tiene en C++ 11 lo siguiente:

enum class E1 : char { Vale1, Vale2 };     // No hay error de sintaxis
enum class E2 : uint32_t { Vale1, Vale2 }; // No hay error de sintaxis

TEST(Strongly_typed_enums)
{
 E1 a = E1::Vale1;
 E2 b = E2::Vale1;
 // int c = E1::Vale1; // Ilegal, imposible asignar enum a int.
 CHECK_EQUAL(1, sizeof(a));
 CHECK_EQUAL(4, sizeof(b));
}

Para que sea fuertemente tipada, enum debe sucederse con la palabra reservada class, seguida de dos puntos y el tipo cuyo tamaño en memoria tendrá la nueva enum. Para más información, ver este documento.

Permitidos varios caracteres > seguidos

Esta posibilidad es bien sencilla, pero que molestaba un poco a los que trabajamos con tipos genéricos, STL y demás. Y es que ya se puede hacer:

TEST(Right_angle_brackets)
{
 vector<vector<int>> v;
 v.push_back(vector<int>());
 v.push_back(vector<int>());
 v.push_back(vector<int>());
 CHECK_EQUAL(3, v.size());
}

En la declaración del vector v no hay error de sintaxis, pues el doble angular >> ya no provoca error en tiempo de compilación al no ser detectado como si fuera operador binario. Este operador de redirección se usa por ejemplo en la segunda sentencia del listado siguiente:

 char a;
 cin >> a;

Para indicarle al objeto cin contenido en el namespace std y parte de la STL que la entrada estándar será almacenada en la variable a. Para más información, ver este link.

Referencias a rvalue

Con la concepción del lenguaje C++, se introdujo el uso de refencias para permitir usar un nombre de variable por otro sin necesidad de recurrir a la indirección (apuntadores). Tomemos el siguiente ejemplo:

 void a(int* p) { *p = 5; }
 void b(int& p) { p = 5; }
 ...
 int myp = 0;
 a(&myp);
 b(p); 

Ambas funciones, a y b producen el mismo efecto, sin embargo a es mucho más ineficiente. Para poder cambiar el valor de p a 5, la función a necesita un apuntador a una variable int y especificar que se cambiará el valor apuntado. Por otro lado, cuando se pasa myp a a debe aplicarse una indirección (operador &). Sin embargo, la función b solo le da un "alias" a la variable myp en su parámetro formal p y lo modifica sin tanto trauma.

Sin embargo, no es posible pasar por referencia un rvalue (expresión a la que no puede asignársele nada). Es decir, lo siguiente es ilegal:

 void b(int& p) { p = 5; }
 int myp() { return 6; }
 ...
 b(myp());

Con las referencias a rvalue, denotadas con el operador &&, es posible hacerlo:

string foo() { return "a"; }

TEST(Rvalue_reference)
{
 // string& f1 = foo();  // Error de sintaxis
 string&& f2 = foo(); // Se mueven los campos del string devuelto por foo, no se copian!
 string f3 = foo();   // Se copian los campos del string devuelto por foo
 CHECK_EQUAL('a', f2[0]);
}

Aunque la lógica sea similar, por debajo lo que se realiza es "mover" la memoria generada por lo que devolvió foo() hacia f2. En el caso de f3 se hace una copia campo por campo del string devuelto, por lo que es ineficiente. Para más información, ver este link.

Manejo de funciones predeterminadas

C++ por defecto brinda cuatro funciones miembro de clases/estructuras:

  • destructor
  • constructor por defecto
  • constructor de copia
  • operador de asignación por copia =

Además, también proporciona otros operadores como new y delete, por ejemplo. Sin embargo, cuando el usuario define un constructor propio, el por defecto desaparece, por lo que habría que implementarlo. Esta implementación es muy posible sea menos eficiente que la que brinda el compilador. Es por ello que se propone lo siguiente:

struct type
{
    int a;
    type() = default; // la reduncia ahora es eficiente
    type(int a) { this->a = a; } // Otro constructor
    virtual ~type(); // virtual requiere una declaración
    type( const type & ); // una simple declaration
};
inline type::type( const type & ) = default; // ahora eficiente
type::~type() = default; // una definición por defecto no inline

struct type2
{
    type2 & operator =( const type2 & ) = delete;
    type2( const type2 & ) = delete;
    type2() = default;
};

TEST(Default_And_Delete_Func)
{
 type t1;
 t1.a = 5;
 type2 t2, t3;
 // t3 = t2; // Inválido, el operador = se ha eliminado
 // type2 t4(t2) // Inválido, el constructor copia se ha eliminado
 type t5(t1); 
 CHECK_EQUAL(5, t5.a);
}

Como se puede ver en caso del tipo type, se han mantenido los constructores y el destructor por defecto, de manera que se puede crear otros constructores sin problemas.

El caso de type2 es otra nueva funcionalidad: eliminar las definiciones del constructor copia y de la asignación por copia (aunque se puedan eliminar otras funciones y sobrecargas de operadores), de manera que las operaciones con el tipo quedan prohibidas. Para más información, ver este link.

Conclusiones

Con estos recursos de nuestro lado, ganamos mucha del azúcar sintáctica y capacidades de las que hoy gozan C# y Java, nada más y nada menos que en C++. Existen otras nuevas mejoras, como las expresiones lambda, tan populares hoy en ambientes .NET, pero vienen en versiones más modernas del compilador g++ (ver aquí), por lo que no han sido abordadas.

También brindamos el vínculo para conocer cuál es el estado del desarrollo de las nuevas funcionalidades en la STL y una referencia online actualizada de los lenguajes C/C++.