[fdo-internals] Incorrect implementation of noncopyable concept

Pierre Dalcourt pierre.dalcourt at autodesk.com
Fri Feb 2 08:33:58 EST 2007


Hi Mateusz,

 

I agree that ideally we should enforce non-copiability in all our
non-copiable classes (across all providers), and that boost provides a
nice shorthand way to achieve this.

 

However, as the code currently stands (the copy constructor is not
explicitly declared private), you will not be able to use it (at least
not outside the class itself).  This is because the destructor is
declared private and you cannot instantiate an object unless you have
access to both the constructor and destructor of that object's class.
So if you try your scenario below, you will get an error "cannot access
private member declared in class 'ArcSDEInsertCommand' [...] see
declaration of ArcSDEInsertCommand::~ArcSDEInsertCommand".

 

Also, since we don't export these methods (using __declspec(dllexport)),
they are not accessible to users outside the provider dll on Windows.  I
realize that this is not the case for Linux, but the FDO API is designed
so that you rarely should be accessing provider-specific classes anyway
(notable exceptions are for provider-specific schema override classes,
and provider-specific commands).  So the kind of scenario you describe
would typically be limited to the code within the shared library.

 

Lastly, even if we do protect the copy constructors across the board,
users could still copy an object if they really wanted to, since there
are always ways around C++'s access mechanisms:

 

  ArcSDEInsertCommand* source_object =
(ArcSDEInsertCommand*)mConnection->CreateCommand(FdoCommandType_Insert);

  ArcSDEInsertCommand* dest_object =
(ArcSDEInsertCommand*)malloc(sizeof(*ins));

  memcpy(dest_object, source_object, sizeof(*source_object));

  //Can now use dest_object even though constructors/destructors are
private

 

I guess what I'm saying is that it's not always worth trying to prevent
people from shooting themselves in the foot because if they really want
to then they'll find a way. :-)

 

Pierre

 

 

-----Original Message-----
From: fdo-internals-bounces at lists.osgeo.org
[mailto:fdo-internals-bounces at lists.osgeo.org] On Behalf Of Mateusz
Loskot
Sent: February 1, 2007 7:28 PM
To: fdo-internals
Subject: [fdo-internals] Incorrect implementation of noncopyable concept

 

Hi,

 

Recently, I've been searching through sources of the ArcSDE provider

(http://svn.osgeo.org/svn/fdoarcsde/) and I found there is used

concept of noncopyable types.

I'd like to report a bug here - as we don't have bug tracker up and

running yet (or I don't know where it is) - because noncopyability

is misused here

In the provider, all is based on declaring public assignment operator,

but not implementing it intentionally. For example here:

 

http://svn.osgeo.org/svn/fdoarcsde/trunk/Providers/ArcSDE/Src/Provider/A
rcSDEInsertCommand.h

 

This approach is insufficient to make a type noncopyable, because I can

still call:

 

A a;

A b(a); // assignment operator is not used

 

but current solution prevents only this case:

 

A a

B b;

b = a; // assignment operator is used, but linker will complain

 

1st issue, is that there is missing copy constructor.

Copy constructor makes (mostly) inseparable pair together with

assignment operator, so they are need to be used together.

 

Let's assume there is a copy constructor added.

 

2nd issue, is that the noncopyable concept is based on declaring copy

ctor and assignment op as private, to cause compiler errors but not

linker errors. Compiler errors are meaningful here ie. saying "can not

access private copy ctor" but linker error is mostly meaningless.

 

Full version of noncopyable concept is implemented as follows:

 

class A

{

public:

    A() {}

private:

    // Blocked copyability - DO NOT IMPLEMENT

    A(A const&);

    A& operator=(A const&);

};

 

int main()

{

    A a;

    A b(a); // can not access private A::A()

    A c;

    c = b;  // can not access priavate A::operator=()

 

    return 0;

}

 

 

Obviously, it's easy to forgot about putting private prototypes for

every noncopyable class, so IMHO it's better to use noncopyable

concept already available from Boost:

 

#include <boost/utility.hpp>

 

class A : boost::noncopyable

{

public:

    A() {}

};

 

IMO, it's better because shorter and doesn't bloat a class definition.

Also, note, the inheritance is intentionally *private*, so the relation

between A and noncopyable types is HAS-A (composition)

but not IS-A (inheritance).

 

Cheers

-- 

Mateusz Loskot

http://mateusz.loskot.net

_______________________________________________

fdo-internals mailing list

fdo-internals at lists.osgeo.org

http://lists.osgeo.org/mailman/listinfo/fdo-internals

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.osgeo.org/pipermail/fdo-internals/attachments/20070202/2547d346/attachment-0001.html


More information about the fdo-internals mailing list