implicit constructor declaration (user annoyed)

S

sb

If there is at least one user-defined constructor, no constructors are
implicitly declared.

struct my_vec : public vector<int> {
double foo;
my_vec(size_t n) : vector<int>(2*n) {}
// oops, no default ctor any more
// have to do a lot of stupid typing now , like:
my_vec() : vector<int>() {}
// etc.
};

Does anyone else find this behavior annoying? Instead, I would prefer
for the compiler to implicitly declare all constructors that are not
declared by the user.
 
J

John Harrison

sb said:
If there is at least one user-defined constructor, no constructors are
implicitly declared.

struct my_vec : public vector<int> {
double foo;
my_vec(size_t n) : vector<int>(2*n) {}
// oops, no default ctor any more
// have to do a lot of stupid typing now , like:
my_vec() : vector<int>() {}
// etc.
};

Does anyone else find this behavior annoying? Instead, I would prefer
for the compiler to implicitly declare all constructors that are not
declared by the user.

Personally I would prefer no constructors to be implicitly defined. But I
think the purpose behind the rules as they are is to define the minimum
implicit constructors will remaining compatible with C.

E.g. this code has to compile as C and C++.

// C code
typedef struct
{
int x;
} X;

X x; // use of implicit default constructor
X y = x; // use of implicit copy constructor

As soon as you define one constructor, you are no longer compatible with C
anyway, so the rules can be tightened.

john
 
J

John Harrison

Actually you don't have to do that

my_vec() {}

is good enough, no too many keystrokes. Or even this

my_vec(size_t n = 0) : vector<int>(2*n) {}

And don't publically inherit from STL container classes, its bad form.

john
 
M

Mike Wahler

sb said:
If there is at least one user-defined constructor, no constructors are
implicitly declared.

struct my_vec : public vector<int> {
double foo;
my_vec(size_t n) : vector<int>(2*n) {}
// oops, no default ctor any more
// have to do a lot of stupid typing now , like:
my_vec() : vector<int>() {}
// etc.
};

Does anyone else find this behavior annoying? Instead, I would prefer
for the compiler to implicitly declare all constructors that are not
declared by the user.

struct my_vec : public vector<int> {
double foo;

public:
my_vec(std::vector<int>::size_type n = 0) // default ctor
: vector<int>(2*n) {} };
};

BTW why are you inheriting from std::vector?

-Mike
 
E

E. Robert Tisdale

sb said:
If there is at least one user-defined constructor, no constructors are
implicitly declared.

struct my_vec: public vector<int> { private:
double foo;
public:
my_vec(size_t n = 0): vector said:
// etc.
};

Does anyone else find this behavior annoying?

Not me.
 
A

Andrey Tarasevich

sb said:
If there is at least one user-defined constructor, no constructors are
implicitly declared.
...

Not exactly true. Copy constructor is always implicitly declared (unless
you explicitly declare copy constructor yourself). Explicit declaration
of non-copy constructor will not suppress implicit declaration of copy
constructor.
 
C

Cy Edmunds

sb said:
If there is at least one user-defined constructor, no constructors are
implicitly declared.

You certainly wrote an unconvincing example:
struct my_vec : public vector<int> {

deriving from std::vector ? ugh
double foo;

public data member. ugh again
my_vec(size_t n) : vector<int>(2*n) {}

this constructor converts integers to my_vec's because you neglected to
declare it explicit
// oops, no default ctor any more
// have to do a lot of stupid typing now , like:

I am tempted to say that you have already done a lot of stupid typing, but
that wouldn't be a quality statement, so I won't. :)
my_vec() : vector<int>() {}

my_vec() {} doesn't look so onerous
// etc.
};

Does anyone else find this behavior annoying? Instead, I would prefer
for the compiler to implicitly declare all constructors that are not
declared by the user.

Perhaps you are a bit too easily annoyed. This rule seems reasonable,
doesn't stop anybody from doing what they want, and in any event is already
established by many years of usage.
 
S

sb

John Harrison said:
Actually you don't have to do that

my_vec() {}

is good enough, no too many keystrokes. Or even this

my_vec(size_t n = 0) : vector<int>(2*n) {}

The snippet is merely an illustration. It could have been

my_vec(size_t n) : vector said:
And don't publically inherit from STL container classes, its bad form.

Arghh! If I had a dime for every time I heard this...

Should I use containment and redefine all methods instead? (lots and
lots of stupid wrapper code). And what if I want my_vec to *BE* a
vector<int> ? No "style" or "possible misuse" considerations will make
up for such braindamage.

I'm sure some people feel very productive when they write

private:
t m_foo;
public:
const t& foo() const { return m_foo; }
t& foo() { return m_foo; }

and then go on to replicate most of the contents of std::vector.
Wheeee! Accessors! Const-correct ones! Wheee! 300 lines of code in one
hour. The manager must be realy proud of me! Thanks. I think I'll
pass.
 
J

John Harrison

And don't publically inherit from STL container classes, its bad form.
Arghh! If I had a dime for every time I heard this...

Should I use containment and redefine all methods instead? (lots and
lots of stupid wrapper code). And what if I want my_vec to *BE* a
vector<int> ? No "style" or "possible misuse" considerations will make
up for such braindamage.

The only case I heard where someone convincingly argued for deriving from a
standard container was a teacher who wanted a class exactly like std::string
but wanted to catch null pointer errors, for the benefit of his students who
were making that sort of error.

Almost every time I see derivation from a standard container it is because
someone wants to avoid the trouble of writing three of four wrapper methods
and doesn't know or doesn't care that they are needlessly inheriting scores
of methods from the parent class.

So I'll revise my advice, don't inherit from std::vector unless you have
good reason and you know what you are doing. I guess there is a small number
of cases where you want a class with *exactly* the same interface as
std::vector but with some additional behaviour, but I think its very rare.

john
 
C

Cy Edmunds

sb said:
"John Harrison" <[email protected]> wrote in message

The snippet is merely an illustration. It could have been



Arghh! If I had a dime for every time I heard this...

Should I use containment and redefine all methods instead? (lots and
lots of stupid wrapper code). And what if I want my_vec to *BE* a
vector<int> ? No "style" or "possible misuse" considerations will make
up for such braindamage.

I'm sure some people feel very productive when they write

private:
t m_foo;
public:
const t& foo() const { return m_foo; }
t& foo() { return m_foo; }

and then go on to replicate most of the contents of std::vector.
Wheeee! Accessors! Const-correct ones! Wheee! 300 lines of code in one
hour. The manager must be realy proud of me! Thanks. I think I'll
pass.

If you are ever interviewing for a job, please make these opinions known to
your interviewer. It might be me, and I certainly wouldn't want to hire you.
 
A

Andre Heinen

I'm sure some people feel very productive when they write

private:
t m_foo;
public:
const t& foo() const { return m_foo; }
t& foo() { return m_foo; }

and then go on to replicate most of the contents of std::vector.
Wheeee! Accessors! Const-correct ones! Wheee! 300 lines of code in one
hour. The manager must be realy proud of me! Thanks. I think I'll
pass.

Actually those 300 lines of code can save you *lots* of time. If
m_foo is public, what will happen when you will have to change
your class's implementation? Imagine this:

class T_Wrapper {
// no const-correctness in this class because it isn't
// what we're talking about
public:
T foo;
void print() {
string s = makeStringRepresentation();
cout << s;
}
string makeStringRepresentation() {
// lots of time-consuming processing here
}
};

And in the client code:

void f(T_Wrapper& tw) {
tw.foo = someValue;
tw.print();
}

One day you decide to optimize makeStringRepresentation():

class T_Wrapper {
public:
T foo;
string cachedStringRep;
bool cacheIsUpToDate;
void print() {
if ( ! cacheIsUpToDate) {
cachedStringRep = makeStringRepresentation();
cacheIsUpToDate = true;
}
cout << cachedStringRep;
}
string makeStringRepresentation() {
// same as above
}
void setFoo(T newFoo) {
foo = newFoo;
cacheIsUpToDate = false; // let's not forget this
}
};

Well, now f() is broken, because it changes foo without setting
cacheIsUpToDate to false. And so is all your client code. You
have to rewrite (or at least check) *everything*.

I think data members should be private even if they are part of
the interface. Unless, of course, you have some good reason to
do otherwise.

And, by the way, const-correctness is useful too...
;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top