False positive warning for initializing forward declared member variables cpp:S3230

Hi, I’m currently using Sonarqube v 8.9.7 and I’m not so satisfied with the cpp:S3230 rule “Do not use the constructor’s initializer list for data member “xy”. Use the in-class initializer instead.”

In general I like in-class initializers of course, but there should be exceptions.

A prominent example is the scaffold code that is created for Qt Widget classes:

#pragma once
#include <QDialog>

namespace Ui {
class MyDialog;

class MyDialog: public QDialog {

    explicit MyDialog( QWidget* parent = 0 );

    Ui::MyDialog* ui;

and the implementation would look like this:

#include "mydialog.h"
#include "ui_mydialog.h"

MyDialog::MyDialog( QWidget* parent ) : QDialog( parent ), ui( new Ui::MyDialog) {
    ui->setupUi( this );

MyDialog::~MyDialog() {
    delete ui;

The ui member has a forward declared type that is defined in ui_mydialog.h. This is a common insulation technique to avoid dependencies between headers. It leaves all the details of the dialog layout outside of the header and I don’t need to recompile components that use the dialog on every layout change. The ui member cannot be initialized in-class easily (One could do in-class initialization from e.g. a static method, but usually we initialize them by calling their constructor).

Of course, a std::unique_ptr would also help here to conform to the rule of zero (cpp core guidelines C20), but that’s a different story.

So my suggestion would be to add the following exception to S3230:
In-class initialization should not be preferred when the type of the member is forward-declared (declared but not defined) in that header.

Thank you for the report @jsinge. I agree that this is indeed FP, and really like your suggested approach of suppressing issues for pointee to incomplete types.
You can track the issue using the following JIRA ticket, that I have created for the issue.

1 Like