Is there a nice way to have a non static value as default argument in a function? I've seen some older responses to the same question which always end up in explicitly writing out the overload. Is this still necessary in C++17?
What I'd like to do is do something akin to
class C {
const int N; //Initialized in constructor
void foo(int x = this->N){
//do something
}
}
instead of having to write
class C {
const int N; //Initialized in constructor
void foo(){
foo(N);
}
void foo(int x){
//do something
}
}
which makes the purpose of the overload less obvious.
One relatively elegant way (in my opinion) would be to use std::optional to accept the argument, and if no argument was provided, use the default from the object:
class C {
const int N_; // Initialized in constructor
public:
C(int x) :N_(x) {}
void foo(std::optional<int> x = std::nullopt) {
std::cout << x.value_or(N_) << std::endl;
}
};
int main() {
C c(7);
c.foo();
c.foo(0);
}
You can find the full explanation of what works/doesn't work in section 11.3.6 of the standard. Subsection 9 describes member access (excerpt):
A non-static member shall not appear in a default argument unless it
appears as the id-expressionof a class member access expression
(8.5.1.5) or unless it is used to form a pointer to member
(8.5.2.1).[Example:The declaration of X::mem1()in the following example
is ill-formed because no object is supplied for the non-static
memberX::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);// error: non-static memberaused as default argument
int mem2(int i = b);// OK; useX::b
static int b;
};
Consider the code
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
struct B
{
public:
void f() { for (auto &v : member) { std::cout << v << std::endl; } }
private:
int member[100];
};
int main()
{
B b{};
b.f();
}
I think this code is guided by $8.5.4/3
List-initialization of an object or reference of type T is defined as follows:
— If the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.
Instead the VS2013 compiler emits all 0xCCCCCCCC implying that it is leaving all elements of b.member as uninitialized. So, it appears it is performing default initialization instead of value initialization.
Please let me know if I am missing something.
What you want to say is this:
int main()
{
B b = {}; // = {} expresses that you want to zero-init the member vars
b.f();
}
If B has a (non-default) constructor or any members with constructors, the above code sample of using ={} may generate a compiler error.
Your code sample can be simplified even further.
#include <iostream>
struct B
{
public:
void f() { std::cout << member << std::endl; }
private:
int member;
};
int main()
{
B b{};
b.f();
}
This produces the output:
-858993460
which is 0xCCCCCCCC in hex, the debug pattern the VC compiler fills memory with in Debug builds. This seems to be a known bug with both VS2012 and VS2013 as reported here.
You can work around the error by defining a constructor that value initializes the data member individually. In your case adding this constructor will result in all elements of member being 0
B() : member{} {}
Consider the following code:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x = T();
}
Since an explicit constructor is called, the above code ends-up zero-initializing all the data members in x.
But I would like to have x zero-initialized even if an explicit is not called. To do that one idea would be to initialize the data members in their declaration, which seems to be okay for T::a. But how can I zero-initialize all the memory occupied by the union by using
the same criteria?
struct T {
int a = 0;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
};
int main() {
T x; // I want x to be zero-initialized
}
You could zeroize using memset:
memset(&x, 0, sizeof(x));
For a union without a user-defined default constructor, value initialization is zero initialization.
However, zero-initialization of a union may not zero all memory, but only the padding and the first member. If the first member isn't the largest, you could be left with non-zero content.
Since you know that s2 is largest, you can make a default constructor that zeros it:
struct T
{
int a;
union {
int s1a;
char s2b[1024];
};
T() : a(), s2b() {}
};
And now
T x;
will be zeroed.
I would suggest to implement a constructor for T:
struct T {
int a;
union {
struct {
int a;
} s1;
struct {
char b[1024];
} s2;
};
T() : a(), s2() {} // <- proper initialisation
};
In this case, I picked the largest member of your union since it's transparent. Otherwise you could explicitly create the union itself.
I was playing with an idea where i can have variables in global scope but not construct them. Note that there IS a placement new being ran. However i'd like to know what is undefined or incorrect about this code
#include <new>
#include <cstdio>
#include <typeinfo>
//#define AlignAs alignas(T)
#define AlignAs
template<class T>struct BlockOf {
AlignAs char t[sizeof(T)];
operator T&() { return reinterpret_cast<T&>(*this); }
~BlockOf(){((T*)&t)->~T(); }
};
struct B{
virtual void v(){}
~B() { printf("B\n"); }
};
struct A: B{
A(){printf("a\n");}
int regularDots;
void v() { printf("A virtual\n"); }
};
BlockOf<A> _a;
A&a=_a;
void init(){
new(&a) A;
}
int main() {
init();
A aa;
a.regularDots=9;
printf("%s %s %d %d\n",
typeid(a).name(),
typeid(aa).name(),
typeid(a).hash_code()==typeid(aa).hash_code(),
sizeof(a) == sizeof(aa)
);
B *b = &a;
b->v();
}
This isn't clear
operator T&() { return *reinterpret_cast<T*>(this); }
Instead use
operator T&() { return reinterpret_cast<T&>(t[0]); }
I think that this is required to point at the first member, but using the array explicitly seems safer to me.
To answer your main question, 3.8p8 contains the restrictions on reusing memory belonging to a variable with static storage duration, and since the original type has a trivial destructor, you should be ok.
If a program ends the lifetime of an object of type T with static (3.7.1), thread (3.7.2), or automatic (3.7.3) storage duration and if T has a non-trivial destructor,
the program must ensure that an object of the original type occupies that same storage location when the implicit destructor call takes place; otherwise the behavior of the program is undefined.
Is there any reason why codeblocks is telling me that I can't make an array? I'm simply trying to do:
const unsigned int ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};
and it's giving me
error: a brace-enclosed initializer is not allowed here before '{' token
I have changed other parts of the initializer, but the error is always saying the same thing. This doesn't seem to make sense, since this is one of the first things I learned in c++.
You say that you did this within a class, as a private variable.
Recall that (at the moment), member variables may not be initialised in the same place where you declare them (with a few exceptions).
struct T {
std::string str = "lol";
};
is not ok. It has to be:
struct T {
std::string str;
T() : str("lol") {}
};
But, to add insult to injury, pre-C++0x you cannot initialise arrays in the ctor-initializer!:
struct T {
const unsigned int array[10];
T() : array({0,1,2,3,4,5,6,7,8,9}) {} // not possible :(
};
And, because your array's elements are const, you can't rely on assignment either:
struct T {
const unsigned int array[10];
T() {
for (int i = 0; i < 10; i++)
array[i] = i; // not possible :(
}
};
However, as some other contributors have quite rightly pointed out, there seems little point in having a copy of the array for each instance of T if you can't modify its elements. Instead, you could use a static member.
So, the following will ultimately solve your problem in what's — probably — the best way:
struct T {
static const unsigned int array[10];
};
const unsigned int T::array[10] = {0,1,2,3,4,5,6,7,8,9};
Hope this helps.
Since this is a private member variable in a class (according to the comment), this is indeed not allowed in C++03.
C++0x, partially supported by many modern compilers, allows the following to compile:
class C
{
const unsigned int ARRAY[10];
public:
C() : ARRAY{0,1,2,3,4,5,6,7,8,9} {}
};
int main()
{
C obj; // contains a non-static const member: non-assignable
}
However, non-static const members only make sense if they contain different values in different instances of the class. If every instance is to contain the same {0,1,2,3,4,5,6,7,8,9}, then you should make it static, which also makes it possible to do this in C++98:
class C
{
static const unsigned int ARRAY[10];
public:
C() {}
};
const unsigned int C::ARRAY[10] = {0,1,2,3,4,5,6,7,8,9};
int main()
{
C obj;
}