M
M
MikhailEdoshin2013-04-05 22:27:31
C++ / C#
MikhailEdoshin, 2013-04-05 22:27:31

What does a C++ class imply with a private constructor and a pair of auto_ptr?

Tell me, please - I have some C / C ++ API. Its C-part is not exactly C, because, although it is declared extern "C", it has C ++ code inside (for example, links, classes, namespaces, etc. are used; that is, the only thing that is there is “C”, are stored function names). The C-plus-plus-part is represented by several classes, but the classes are “empty” - all their code is right there in the header files in the form of inline functions, which, in turn, call methods from the pseudo-C part.

I, accordingly, ignore the empty part and work with the pseudo-C part. In addition, I work from regular C - I simply redeclared the functions myself, replacing references with pointers, declared incomplete types where necessary, and so on. Everything works great.

But there is a nuance.What I don't quite understand is what the author of the original API meant. For example:

1. The function returns a constant reference, i.e.

const foo::Bar& myfunc(); 

In my C adapter, I override it like this:

const foo_Bar_t* myfunc();

Do I understand correctly that I cannot store this pointer after returning from the function?

2. A class with a private-constructor and an accompanying auto_ptr. It looks like this:

namespace foo {
    class Baz
    {
        private: 
            Baz();
            Baz( const Baz& source);
    };
    class BazAutoPtr: public std:auto_ptr<Baz>
    {
        public:
            inline BazAutoPtr();
    };
} 

BazAutoPtr()is the following:

inline BazAutoPtr::BazAutoPtr() {
    this->operator=(*static cast<Baz>(&std::auto_ptr<element_type>(Baz_Constructor())));
}

Here Baz_Constructoris a function from the pseudo-C part that actually creates a new Baz and returns a pointer:

foo::Baz* Baz_Constructor();

As I understand all this, objects foo::Bazcannot be created directly, only through auto_ptr. The code in BazAutoPtr()calls the real constructor and replaces the newly created empty object there. I also imagine the point auto_ptr- to allocate an object on the heap and automatically delete it when the function exits. What I don't understand is what did the API author mean by building this construct? Did he mean that I should not store instances at all, foo::Bazor something else?

(Purely technically, I keep them for now without visible consequences; but who knows.)

Answer the question

In order to leave comments, you need to log in

3 answer(s)
M
Monnoroch, 2013-04-05
@Monnoroch

It seems to me that with this approach you will still catch fifty different UBs, so in any case I don’t advise you to do this, but I advise you to write wrappers. And the author of the code is very strange. Not only has auto_ptr been deprecated for a long time, but also inheriting from it is clearly dumb. Summarizing, here the author could mean anything, from syntactic sugar to some rules of use, and it seems to me that there is no way to understand except to ask him.

L
Lolshto, 2013-04-05
@Lol4t0

const foo::Bar& myfunc(); 

In my C adapter, I override it like this:
const foo_Bar_t* myfunc();

Generally speaking, this is already undefined behavior, because the standard does not guarantee that references will be implemented via pointers.
Do I understand correctly that I cannot store this pointer after returning from the function?

It all depends on what the function does:
const int g = 1;
struct S
{
  const int & foo() const
  {
    return v;
  }
  const int & bar() const
  {
    return g;
  }
  int v = 0;
};

const int & foobar()
{
  S s;
  //return s.foo(); // oops
  return s.bar(); //ok
}

int main(int argc, char const *argv[])
{
  return foobar();
}

Then you have incorrect code:
How should it work static_cast от std::auto_ptr<Baz>*in Baz?
I'm assuming you actually have:
this->operator=(*static_cast<BazAutoPtr*>(&std::auto_ptr<element_type>(Baz_Constructor())));

Which, in general, is also undefined behavior, because
- error: taking address of temporary
- static_cast an object to a type of which it is not actually an object.
Apparently, this construction was supposed to express approximately the same as
inline BazAutoPtr():std::auto_ptr<Baz>(Baz_Constructor()){}

In general, the most practical advice here is to tie it with the code in which this is written.

D
Door, 2013-04-05
@Door

I think in the first case, it would be best to simply return foo_Bar_t(depends on what's inside foo_Bar_t).
And the second is complete nonsense: you cannot inherit from std:auto_ptr... The std:auto_ptroperator for taking the address ( operator&) is not redefined in B and type casting std:auto_ptr<Baz>*to Baz - should not compile. And if you already write such nonsense, then it's probably better to do this:

inline BazAutoPtr::BazAutoPtr()
{
    reset(Baz_Constructor());
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question