[boost] [optional] Types without assignment operator

14 views
Skip to first unread message

Adam Badura

unread,
Nov 14, 2012, 6:39:26 AM11/14/12
to bo...@lists.boost.org
I use boost::optional for deferred construction.

Something similar to the idea described in "Bypassing expensive unnecessary
default construction" in Boost.Optional documentation. Only in my case I do
this because the mentioned construction requires virtual function calls and
this cannot be done in owning object constructor and has to be postponed.

So instead of accessing the object directly I always access it by a
function. That function first checks if the object is already constructed
(boost::optional is initialized) and if so just returns it. Otherwise it
first constructs it.

That approach requires only copy construction (or even move construction if
boost::optional would support moving in the first place). Yet due to
implementation details the embedded type has to be assignable as well. Even
thou assignment operator will never be called (in this scenario).

Is there a way to avoid this issue?

If not then how about adding a function like "assign" (possibly named
otherwise or with additional defaulting argument) which could assign by
first destroying old object (if any) and then copy/move constructing a new
one.

This would obviously be bad from exception safety (guarantees) point of
view, but well... don't call the function if you don't like that. And in
scenarios like mine it would not be an issue since there would be no object
to destroy anyway. (Also the function could assert/throw on that
condition...)


Now the Synopsis part of the Boost.Optional documentation does mention
(Typed)InPlaceFactory assign operators which do look promising for solving
this issue. But firstly they are not documented in following Detailed
Semantics part. There is even no link in the Synopsis. (Is this docs bug? In
which part? Missing docs or extra functions?) And secondly
(Typed)InPlaceFactory support is "intrusive". I cannot add it to a class
without changing the class itself. And in my case I cannot change the class
(boost::program_options::options_description - why cannot it be copy
assigned, that I don't know...). Maybe adding some extra wrapper would help
but I don't think it would be a solution. Rather a somewhat ugly workaround.


Adam Badura



_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Andrzej Krzemienski

unread,
Nov 14, 2012, 6:52:27 AM11/14/12
to bo...@lists.boost.org
2012/11/14 Adam Badura <aba...@o2.pl>

>
> So instead of accessing the object directly I always access it by a
> function. That function first checks if the object is already constructed
> (boost::optional is initialized) and if so just returns it. Otherwise it
> first constructs it.
>

I am having problems imagining the situation. Can't you change your
function so that returns real object rather than optional object if it is
initialized? Perhaps using optional reference to an object would solve your
problem?



> Now the Synopsis part of the Boost.Optional documentation does mention
> (Typed)InPlaceFactory assign operators which do look promising for solving
> this issue. But firstly they are not documented in following Detailed
> Semantics part. There is even no link in the Synopsis. (Is this docs bug?
> In which part? Missing docs or extra functions?)


See this link:
http://www.boost.org/doc/libs/1_52_0/libs/utility/in_place_factories.html
Indeed, there is no path to it from the documentation root.


> And secondly (Typed)InPlaceFactory support is "intrusive". I cannot add it
> to a class without changing the class itself. And in my case I cannot
> change the class (boost::program_options::options_description - why cannot
> it be copy assigned, that I don't know...). Maybe adding some extra wrapper
> would help but I don't think it would be a solution. Rather a somewhat ugly
> workaround.
>

Intrusive? "in_place" is used to initialize or assign boost::optional. Do
you want to use it for your own class? THis does not appear the right way
to go.

Regards,
&rzej

Andrey Semashev

unread,
Nov 14, 2012, 6:56:54 AM11/14/12
to bo...@lists.boost.org
On Wed, Nov 14, 2012 at 3:39 PM, Adam Badura <aba...@o2.pl> wrote:
> I use boost::optional for deferred construction.
>
> Something similar to the idea described in "Bypassing expensive unnecessary
> default construction" in Boost.Optional documentation. Only in my case I do
> this because the mentioned construction requires virtual function calls and
> this cannot be done in owning object constructor and has to be postponed.
>
> So instead of accessing the object directly I always access it by a
> function. That function first checks if the object is already constructed
> (boost::optional is initialized) and if so just returns it. Otherwise it
> first constructs it.
>
> That approach requires only copy construction (or even move construction if
> boost::optional would support moving in the first place). Yet due to
> implementation details the embedded type has to be assignable as well. Even
> thou assignment operator will never be called (in this scenario).
>
> Is there a way to avoid this issue?
>
> Now the Synopsis part of the Boost.Optional documentation does mention
> (Typed)InPlaceFactory assign operators which do look promising for solving
> this issue. But firstly they are not documented in following Detailed
> Semantics part. There is even no link in the Synopsis. (Is this docs bug? In
> which part? Missing docs or extra functions?) And secondly
> (Typed)InPlaceFactory support is "intrusive". I cannot add it to a class
> without changing the class itself. And in my case I cannot change the class
> (boost::program_options::options_description - why cannot it be copy
> assigned, that I don't know...). Maybe adding some extra wrapper would help
> but I don't think it would be a solution. Rather a somewhat ugly workaround.

In-place factories are not intrusive, you can in-place construct value
of any type, as long as it has the necessary constructor. The
description is available here:

http://www.boost.org/doc/libs/release/libs/optional/doc/html/boost_optional/in_place_factories.html

AFAIR, assignment operator is not required by optional if you use
in-place factories in assignment. It is only required if you use
regular assignment with optional.

Adam Badura

unread,
Nov 14, 2012, 7:11:31 AM11/14/12
to bo...@lists.boost.org
> >
> > So instead of accessing the object directly I always access it by a
> > function. That function first checks if the object is already
> > constructed
> > (boost::optional is initialized) and if so just returns it. Otherwise it
> > first constructs it.
> >
>
> I am having problems imagining the situation. Can't you change your
> function so that returns real object rather than optional object if it is
> initialized? Perhaps using optional reference to an object would solve
> your
> problem?

Example follows:

>>>>>>>>>>

class Owner {
public:
Owner()
: m_value()
{
}

SomeType const& getValue() const {
if ( !m_value )
m_value = constructValue();
return *m_value;
}

protected:
virtual int virtualFunction() const = 0;

private:
SomeType constructValue() const {
SomeType object( /*...*/ );
object.callThis();
object.assignHere = virtualFunction();
return object;
}

mutable boost::optional< SomeType > m_value;
};

<<<<<<<<<<

Now SomeType does not support copying by assignment but it does support copy
construction. It might be silly or maybe not. It does not matter since it is
not my type and I have to deal with it (it is
boost::program_options::options_description).

I cannot construct m_value in Owner constructor since (as can be seen in
"constructValue" function) it requires a virtual call (to
"virtualFunction"). Also note that "constructValue" is not just a simple
construction.

Obviously I could avoid the problem by not storing "m_value" in first place.
But for other reasons (like for example efficiency, but not only) I would
like to store it.

Adam Badura

Adam Badura

unread,
Nov 14, 2012, 7:17:02 AM11/14/12
to bo...@lists.boost.org
> In-place factories are not intrusive, you can in-place construct value
> of any type, as long as it has the necessary constructor. The
> description is available here:
>
> http://www.boost.org/doc/libs/release/libs/optional/doc/html/boost_optional/in_place_factories.html

OK, I was wrong here. It is intrusive regarding boost::optional (it has to
have those extra constructors and assignments) and not my embedded type.
Should have looked at that closer before writing.

But it doesn't really change things because as I showed in example in a
reply to "Andrzej Krzemienski" the construction is non-trivial in the sense
that it is not just a call to constructor but also other operations.

On the other hand I could do those other operations in getValue() function
just after assigning to m_value. And that would solve the issue. In a rather
convoluted way but maybe this is too subjective to be a matter here.


And since those missing links are a documentation bug should I report it
somehow? How? Where?

Adam Badura

Andrzej Krzemienski

unread,
Nov 14, 2012, 7:33:28 AM11/14/12
to bo...@lists.boost.org
2012/11/14 Adam Badura <aba...@o2.pl>
Would the following work for you?

class Owner {
public:
Owner() : m_value() {}

SomeType const& getValue() const {
if ( !m_value )
constructValue(m_value);
return *m_value;
}

protected:
virtual int virtualFunction() const = 0;

private:
static void constructValue(SomeType & target) const {
SomeType object( /*...*/ );
object.callThis();
object.assignHere = virtualFunction();
target = boost::in_place(object);
}

mutable boost::optional< SomeType > m_value;
};

Adam Badura

unread,
Nov 14, 2012, 7:44:38 AM11/14/12
to bo...@lists.boost.org
> Would the following work for you?
>
> class Owner {
> public:
> Owner() : m_value() {}
>
> SomeType const& getValue() const {
> if ( !m_value )
> constructValue(m_value);
> return *m_value;
> }
>
> protected:
> virtual int virtualFunction() const = 0;
>
> private:
> static void constructValue(SomeType & target) const {
> SomeType object( /*...*/ );
> object.callThis();
> object.assignHere = virtualFunction();
> target = boost::in_place(object);
> }
>
> mutable boost::optional< SomeType > m_value;
> };

Not quite. Your code has errors:

(1) constructValue takes SomeType& while it should boost::optional< SomeType
>&.

(2) constructValue must not be const since it is static.

(3) constructValue must not be static in the first place anyway, since it
calls member function "virtualFunction".

But those are just minor issues.

The approach by itself does work. I realized that when answering to "Andrey
Semashev" and already applied to solution to my code. In fact your
proposition is even somewhat better than mine by encapsulating entire
construction process in a single function and calling in_place copy
constructor rather than ordinary constructor.

Thanks!

Adam Badura

Andrzej Krzemienski

unread,
Nov 14, 2012, 7:59:19 AM11/14/12
to bo...@lists.boost.org
2012/11/14 Adam Badura <aba...@o2.pl>

>
> And since those missing links are a documentation bug should I report it
> somehow? How? Where?


See here for instructions:
http://www.boost.org/support/bugs.html

You can also consider the lack of Optional's move operations a bug.

Regards,
&rzej

Adam Badura

unread,
Nov 14, 2012, 8:58:09 AM11/14/12
to bo...@lists.boost.org
Ticket for documentation: https://svn.boost.org/trac/boost/ticket/7691 (I
just added it)
Ticker for move support: https://svn.boost.org/trac/boost/ticket/1841 (was
already there)
Reply all
Reply to author
Forward
0 new messages