Constructor question...

Discussion in 'C++' started by TDH1978, Feb 13, 2013.

  1. TDH1978

    TDH1978 Guest

    I have a class where the default constructor is disabled, and the only
    constructor takes one parameter. The construction of the object
    depends on a condition:

    if (cond)
    A a(x);
    else
    A a(y);

    The problem is that the object 'a' goes out of scope after the 'if'
    statement, and I do not want to use pointers, like:

    A* aptr;
    if (cond)
    aptr = new A(x)
    else
    aptr = new A(y);


    Is there a more elegant solution?
    TDH1978, Feb 13, 2013
    #1
    1. Advertising

  2. TDH1978

    Luca Risolia Guest

    On 13/02/2013 02:29, TDH1978 wrote:
    > I have a class where the default constructor is disabled, and the only
    > constructor takes one parameter. The construction of the object depends
    > on a condition:
    >
    > if (cond)
    > A a(x);
    > else
    > A a(y);
    >
    > The problem is that the object 'a' goes out of scope after the 'if'
    > statement, and I do not want to use pointers, like:
    >
    > A* aptr;
    > if (cond)
    > aptr = new A(x)
    > else
    > aptr = new A(y);
    >
    >
    > Is there a more elegant solution?
    >


    You did not define A and the type of cond, x and y, so it's not possible
    to give you a general answer. Anyway, see if A a(cond ? x : y) works for
    you.
    Luca Risolia, Feb 13, 2013
    #2
    1. Advertising

  3. TDH1978

    Öö Tiib Guest

    On Wednesday, 13 February 2013 03:29:15 UTC+2, TDH1978 wrote:
    > I have a class where the default constructor is disabled, and the only
    > constructor takes one parameter. The construction of the object
    > depends on a condition:


    Better write that also in C++, English is too ambiguous to forward lot
    of (possibly important) details.

    > if (cond)
    > A a(x);
    > else
    > A a(y);
    >
    > The problem is that the object 'a' goes out of scope after the 'if'
    > statement, and I do not want to use pointers, like:
    >
    > A* aptr;
    > if (cond)
    > aptr = new A(x)
    > else
    > aptr = new A(y);
    >
    > Is there a more elegant solution?


    Multitude. For example separate deciding the argument and constructing a:

    AParamType arg = cond ? x : y;

    A a(arg);
    Öö Tiib, Feb 13, 2013
    #3
  4. "TDH1978" wrote in message news:kfeq82$ekg$...
    >
    >I have a class where the default constructor is disabled, and the only
    >constructor takes one parameter. The construction of the object depends on
    >a condition:
    >
    > if (cond)
    > A a(x);
    > else
    > A a(y);
    >
    >The problem is that the object 'a' goes out of scope after the 'if'
    >statement, and I do not want to use pointers, like:
    >
    > A* aptr;
    > if (cond)
    > aptr = new A(x)
    > else
    > aptr = new A(y);
    >
    >
    >Is there a more elegant solution?


    A a (cond ? x : y);
    Fred Zwarts \(KVI\), Feb 13, 2013
    #4
  5. TDH1978

    Adam Wysocki Guest

    TDH1978 <> wrote:

    > if (cond)
    > A a(x);
    > else
    > A a(y);


    Try:

    A a(cond ? x : y);

    Note that x and y have to be same type, so this will not work:

    class B {};
    class D1: public B {};
    class D2: public B {};

    class A
    {
    public:
    A(B) {}
    };

    void fn(int i)
    {
    D1 d1;
    D2 d2;
    A a(i == 5 ? d1 : d2);
    }

    AW
    Adam Wysocki, Feb 13, 2013
    #5
  6. TDH1978

    Adam Wysocki Guest

    TDH1978 <> wrote:

    > The problem is that the object 'a' goes out of scope after the 'if'
    > statement, and I do not want to use pointers, like:


    In other situations and more complex conditions, when you don't want to
    use ?: operator, you can consider using auto_ptr.

    AW
    Adam Wysocki, Feb 13, 2013
    #6
  7. Andy Champ <> wrote:
    > On 13/02/2013 02:20, Luca Risolia wrote:
    >> On 13/02/2013 02:29, TDH1978 wrote:
    >>> I have a class where the default constructor is disabled, and the only
    >>> constructor takes one parameter.

    <snip>
    >>> Is there a more elegant solution?

    <snip>
    >> Anyway, see if A a(cond ? x : y) works for you.

    >
    > This assumes that there is only one constructor for A.


    That's exactly what the OP said.

    Tobi
    Tobias Müller, Feb 13, 2013
    #7
  8. Adam Wysocki <> wrote:
    > TDH1978 <> wrote:
    >
    >> if (cond)
    >> A a(x);
    >> else
    >> A a(y);

    >
    > Try:
    >
    > A a(cond ? x : y);
    >
    > Note that x and y have to be same type,


    That's not true. Essentially, it works if one of the two is convertible to
    the type (or a reference of the type) of the other.
    (It's actually a bit more complex and sometimes the result is a temporary)

    > so this will not work:
    >
    > class B {};
    > class D1: public B {};
    > class D2: public B {};
    >
    > class A
    > {
    > public:
    > A(B) {}
    > };
    >
    > void fn(int i)
    > {
    > D1 d1;
    > D2 d2;
    > A a(i == 5 ? d1 : d2);
    > }


    A a(i == 5 ? (B&)d1 : d2); // Now it works

    Tobi
    Tobias Müller, Feb 13, 2013
    #8
  9. TDH1978

    Adam Wysocki Guest

    Tobias Müller <> wrote:

    > That's not true. Essentially, it works if one of the two is convertible to
    > the type (or a reference of the type) of the other.


    Thanks for the clarification.

    AW
    Adam Wysocki, Feb 19, 2013
    #9
  10. On Feb 13, 6:30 am, Tobias Müller <> wrote:
    > Andy Champ <> wrote:
    > > On 13/02/2013 02:20, Luca Risolia wrote:
    > >> On 13/02/2013 02:29, TDH1978 wrote:
    > >>> I have a class where the default constructor is disabled, and the only
    > >>> constructor takes one parameter.

    > <snip>
    > >>> Is there a more elegant solution?

    > <snip>
    > >> Anyway, see if A a(cond ? x : y) works for you.

    >
    > > This assumes that there is only one constructor for A.

    >
    > That's exactly what the OP said.
    >


    The expression involving ternary operator requires that 'x' and 'y' be
    of the same type.

    Luca Risolia is right in that the OP hasn't provided sufficient
    information to give an accurate answer.
    Anand Hariharan, Feb 19, 2013
    #10
  11. Anand Hariharan <> wrote:
    > On Feb 13, 6:30 am, Tobias Müller <> wrote:
    >> Andy Champ <> wrote:
    >>> On 13/02/2013 02:20, Luca Risolia wrote:

    <snip>
    >>>> Anyway, see if A a(cond ? x : y) works for you.

    >>
    >>> This assumes that there is only one constructor for A.

    >>
    >> That's exactly what the OP said.

    >
    > The expression involving ternary operator requires that 'x' and 'y' be
    > of the same type.


    That's not quite true. One of them has to be convertible to the type of the
    other.
    Since A has only one constructor, they have to be convertible to a common
    type (let's call it Z) anyway. That means, with an appropriate cast on
    either x or y, the ternary operator is perfectly suitable for any possible
    combination of x, y and Z.

    > Luca Risolia is right in that the OP hasn't provided sufficient
    > information to give an accurate answer.


    That's where we disagree.

    Tobi
    Tobias Müller, Feb 19, 2013
    #11
  12. TDH1978

    Luca Risolia Guest

    On 19/02/2013 20:40, Tobias Müller wrote:
    > That's not quite true. One of them has to be convertible to the type of the
    > other.
    > Since A has only one constructor, they have to be convertible to a common
    > type (let's call it Z) anyway. That means, with an appropriate cast on
    > either x or y, the ternary operator is perfectly suitable for any possible
    > combination of x, y and Z.
    >
    >> Luca Risolia is right in that the OP hasn't provided sufficient
    >> information to give an accurate answer.

    >
    > That's where we disagree.


    If you define A (according to the OP's requirements), x and y as
    follows, then, although the OP example compiles without problems, "A
    a(cond ? x : y);" will not compile:

    struct A {
    A(int = 0) {};
    operator int() {};
    };

    int main() {
    int x;
    A y;
    A a(true ? x : y); // error: ambiguous
    }

    source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
    be converted to 'A' and vice versa
    A a(true ? x : y);

    Therefore, as I said, the answer to the OP question in general depends
    on the definition of A and the types of x and y, which were not given in
    the question.
    Luca Risolia, Feb 19, 2013
    #12
  13. TDH1978

    Öö Tiib Guest

    On Wednesday, 20 February 2013 01:31:45 UTC+2, Luca Risolia wrote:
    > If you define A (according to the OP's requirements), x and y as
    > follows, then, although the OP example compiles without problems, "A
    > a(cond ? x : y);" will not compile:
    >
    > struct A {
    > A(int = 0) {};
    > operator int() {};
    > };


    Such class won't pass majority of reviews. Anything that is converting to
    arithmetic type silently won't pass. It is close to worst error-prone
    thing that C++ can deliver.

    > int main() {
    > int x;
    > A y;
    > A a(true ? x : y); // error: ambiguous
    > }
    >
    > source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
    > be converted to 'A' and vice versa
    > A a(true ? x : y);


    The error message would perfectly tell the reason why the whole code
    should be deleted ... so that is great then. Code deleted, no problem.
    Öö Tiib, Feb 19, 2013
    #13
  14. TDH1978

    Luca Risolia Guest

    On 20/02/2013 00:44, Öö Tiib wrote:
    >> struct A {
    >> A(int = 0) {};
    >> operator int() {};
    >> };

    >
    > Such class won't pass majority of reviews. Anything that is converting to
    > arithmetic type silently won't pass. It is close to worst error-prone
    > thing that C++ can deliver.


    That's perfectly evident, but it's not relevant to the question. If you
    want, you can easily generalize the example to any type; after all,
    despite of any reviews, it's quite common to see "lazy" data types
    implemented with *implicit* convertions from one type to another one
    *and* viceversa. I personally consider that a design flaw, yes, but,
    again, this is another issue.

    >> source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
    >> be converted to 'A' and vice versa
    >> A a(true ? x : y);

    >
    > The error message would perfectly tell the reason why the whole code
    > should be deleted ... so that is great then. Code deleted, no problem.


    There is no need to delete the whole code. The solution is to modify the
    type by making the convertion in one direction explicit.
    Note that in C++11 if you make the operator explicit, "A a (cond ? x :
    y)" will compile without modifications.
    Luca Risolia, Feb 20, 2013
    #14
  15. TDH1978

    Öö Tiib Guest

    On Wednesday, 20 February 2013 04:03:17 UTC+2, Luca Risolia wrote:
    > On 20/02/2013 00:44, Öö Tiib wrote:
    > >> struct A {
    > >> A(int = 0) {};
    > >> operator int() {};
    > >> };

    > >
    > > Such class won't pass majority of reviews. Anything that is converting to
    > > arithmetic type silently won't pass. It is close to worst error-prone
    > > thing that C++ can deliver.

    >
    > That's perfectly evident, but it's not relevant to the question. If you
    > want, you can easily generalize the example to any type; after all,
    > despite of any reviews, it's quite common to see "lazy" data types
    > implemented with *implicit* convertions from one type to another one
    > *and* viceversa. I personally consider that a design flaw, yes, but,
    > again, this is another issue.


    My point was that if OP uses that obscure and generally frowned upon
    idiom (round-trip implicit conversions) then, yes, you are right
    that some of the suggestions that we provide do not compile.

    However on that case he likely benefits more from suggestion to stop
    using that idiom than from a technique how to construct same object
    of such a type in different branches.

    > >> source.cpp:9:13: error: conditional expression is ambiguous; 'int' can
    > >> be converted to 'A' and vice versa
    > >> A a(true ? x : y);

    > >
    > > The error message would perfectly tell the reason why the whole code
    > > should be deleted ... so that is great then. Code deleted, no problem.

    >
    > There is no need to delete the whole code. The solution is to modify the
    > type by making the convertion in one direction explicit.
    > Note that in C++11 if you make the operator explicit, "A a (cond ? x :
    > y)" will compile without modifications.


    There you are correct indeed, I was too harsh in my judgement.
    Öö Tiib, Feb 20, 2013
    #15
  16. TDH1978

    James Kanze Guest

    On Tuesday, February 19, 2013 7:40:28 PM UTC, Tobias Müller wrote:
    > Anand Hariharan <> wrote:
    > > On Feb 13, 6:30 am, Tobias Müller <> wrote:
    > >> Andy Champ <> wrote:
    > >>> On 13/02/2013 02:20, Luca Risolia wrote:
    > >>>> Anyway, see if A a(cond ? x : y) works for you.
    > >>> This assumes that there is only one constructor for A.
    > >> That's exactly what the OP said.


    > > The expression involving ternary operator requires that 'x' and 'y' be
    > > of the same type.


    > That's not quite true. One of them has to be convertible to the type of the
    > other.


    That's not quite true either (although it is close enough for
    most use). More precisely, one of them has to be implicitly
    convertible to the type of the other, *or* one of them must be a
    throw expression.

    One of the most frustrating consequences of this rule is that:

    Base* pb = cond ? new Derived1 : new Derived2;4

    doesn't work.

    > Since A has only one constructor, they have to be convertible to a common
    > type (let's call it Z) anyway. That means, with an appropriate cast on
    > either x or y, the ternary operator is perfectly suitable for any possible
    > combination of x, y and Z.


    There's nothing in the original question which indicates whether
    the constructor called should be the same or not. If the
    constructor ultimately called should be the same.

    A a( cond ? x : y );

    , possibly with explicit conversions, is fine. Otherwise, if
    the class supports copy:

    A a ( cond ? A( x ) : A( y ) );

    Otherwise, something like:

    A const& a = cond ? A( x ) : A( y );

    might work, but only for a const reference.

    If none of the above work, then the OP will have to use:

    std::unique_ptr<A> aptr( cond ? new A( x ) : new A( y ) );
    A& a = *aptr;

    Unless A is very simple, the cost of the extra allocation is
    probably not significant.

    --
    James
    James Kanze, Feb 24, 2013
    #16
  17. James Kanze <> wrote:
    > On Tuesday, February 19, 2013 7:40:28 PM UTC, Tobias Müller wrote:
    >> Anand Hariharan <> wrote:
    >>> The expression involving ternary operator requires that 'x' and 'y' be
    >>> of the same type.

    >
    >> That's not quite true. One of them has to be convertible to the type of the
    >> other.

    >
    > That's not quite true either (although it is close enough for
    > most use). More precisely, one of them has to be implicitly
    > convertible to the type of the other, *or* one of them must be a
    > throw expression.


    You're right of course. The 'implicitly' is important, the throwing not so
    in that case.

    > One of the most frustrating consequences of this rule is that:
    >
    > Base* pb = cond ? new Derived1 : new Derived2;4
    >
    > doesn't work.
    >
    >> Since A has only one constructor, they have to be convertible to a common
    >> type (let's call it Z) anyway. That means, with an appropriate cast on
    >> either x or y, the ternary operator is perfectly suitable for any possible
    >> combination of x, y and Z.

    >
    > There's nothing in the original question which indicates whether
    > the constructor called should be the same or not.


    Yes there is. The OP wrote about the only constructor of A, so I assumed
    that's the one to be called in both cases.
    Unfortunately I snipped that part away.

    > If the constructor ultimately called should be the same.
    >
    > A a( cond ? x : y );
    >
    > , possibly with explicit conversions, is fine. Otherwise, if
    > the class supports copy:
    >
    > A a ( cond ? A( x ) : A( y ) );
    >
    > Otherwise, something like:
    >
    > A const& a = cond ? A( x ) : A( y );
    >
    > might work, but only for a const reference.
    >
    > If none of the above work, then the OP will have to use:
    >
    > std::unique_ptr<A> aptr( cond ? new A( x ) : new A( y ) );
    > A& a = *aptr;
    >
    > Unless A is very simple, the cost of the extra allocation is
    > probably not significant.


    That's difficult to say. One single allocation is certainly not
    significant, but if it happens very often or if you use dynamic allocation
    everywhere, things look different.

    Tobi
    Tobias Müller, Feb 25, 2013
    #17
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Giulio
    Replies:
    9
    Views:
    1,028
    Patrick Kowalzick
    Jun 25, 2003
  2. Brett Irving
    Replies:
    3
    Views:
    3,319
    John Harrison
    Jun 29, 2003
  3. lallous
    Replies:
    5
    Views:
    8,800
    David Harmon
    Jan 23, 2004
  4. Replies:
    6
    Views:
    490
  5. Generic Usenet Account
    Replies:
    10
    Views:
    2,197
Loading...

Share This Page