Это неопределенное поведение. Поскольку язык не требует, чтобы this
передавался как параметр, он может не передаваться вообще.
Например, если компилятор может выяснить, что объект является синглтоном, он может избежать передачи this
в качестве параметра и использовать глобальный символ, когда явно требуется адрес this
(как в случае va_start). Теоретически, компилятор может сгенерировать код, чтобы компенсировать это в va_start
(в конце концов, компилятор знает, что это одиночный код), но это не требуется по стандарту.
Подумайте о чем-то вроде:
class single {
public:
single(const single& )= delete;
single &operator=(const single& )= delete;
static single & get() {
// this is the only place that can construct the object.
// this address is know not later than load time:
static single x;
return x;
}
void print(...) {
va_list args;
va_start (args, this);
vprintf ("%d\n", args);
va_end (args);
}
private:
single() = default;
};
Некоторые компиляторы, такие как clang 8.0.0, выдают предупреждение для приведенного выше кода:
prog.cc:15:23: warning: second argument to 'va_start' is not the last named parameter [-Wvarargs] va_start (args, this);
Несмотря на предупреждение, работает нормально . В общем, это ничего не доказывает, но иметь предупреждение - плохая идея.
Примечание : Я не знаю ни одного компилятора, который обнаруживает синглтоны и обрабатывает их специально, но язык не запрещает такую оптимизацию. Если это не сделано вашим компилятором сегодня, это может быть сделано завтра другим компилятором.
Примечание 2: несмотря на все это, на практике может быть целесообразно передать это va_start
. Даже если это работает, не стоит делать что-то, что не гарантировано стандартом.
Примечание 3 : одну и ту же одноэлементную оптимизацию нельзя применить к таким параметрам, как:
void foo(singleton * x, ...)
Его нельзя оптимизировать, поскольку он может иметь одно из двух значений, указывать на синглтон или быть nullptr
. Это означает, что данная проблема оптимизации здесь не применима.