开发者

Declaring a type without providing the name

I've tested some code on gcc in debug mode, but not sure it will work correct for other compilers.

My question is how will any compiler optimize the following c++ code (make_auto macro):

class A
{
private:
 void *ptr;
public:
  A(void* _ptr) {ptr = _ptr;}
  ~A() {free(ptr);}
};

#define make_auto(ptr) A(ptr)

int main ()
{
   char *a = (char*)malloc(sizeof(char)),*b = (char*)malloc(size开发者_StackOverflow中文版of(char));
   make_auto(a);
   make_auto(b);
   return 0;
}

Will it always call constructor and destructor of A? Or will compiler optimize this code in any case and delete A(ptr) calls, because it can think that it will not be used more.

UPD:

I know about boost and std::auto_ptr. I have own memory manager that is controlling fragmentation of memory and helps to avoid memory leaks. Now I want to "teach" my memory manager to create auto_ptrs like it is doing in boost and stl.

UPD2:

Here is complete code, that i'm using and that i thought is working correct:

    class AutoPtr
    {
    private:
        void *ptr;
        Application *app;
    public:
        AutoPtr(Application *_app,void *a)
        {
            printf("constructor called\n");
            ptr = a;
            app = _app;
        }
        ~AutoPtr()
        {
            fast_free(app,ptr);
            printf("destructor called\n");
        }

    };
#define make_auto_ptr(app,ptr)  AutoPtr(app,ptr)
    static void AutoPtrTest1()
    {
        test_declare_app

        char *a = fast_alloc(app,char,20);
        char *b = fast_alloc(app,char,11);

        {
            make_auto_ptr(app,a);
            make_auto_ptr(app,b);
        }


        test_free_app
        printf("Autoptrtest1 passed\n");                
    }

Output:

constructor called destructor called constructor called destructor called Autoptrtest1 passed

So it doesn't work correct as i thought (i didn't check destructor calls). But it calls constructors twice as i said before . How to change make_auto_ptr for auto-declaring auto-ptrs?


Nothing happens, because your code is ill-formed. A(a); and A(b); declare a and b. Since a has already been declared, and A in any case has no default constructor, the compiler shall emit a diagnostic.

If you fix these issues, then the compiler is allowed to optimize away these, if the malloc and free you are using are the Standard libraries' functions, because that code really has no observable side effects.

An optimizing compiler should know about the special meaning of malloc and free, and I wouldn't be surprised to see it optimize this away. But for whatever reasons there might be, I can also imagine the compiler doesn't optimize it away. It really depends on your compiler and the flags it uses, but the Standard definitely allows it to optimize here.

Here is the code that clang -O2 -emit-llvm -S main1.cpp -o - outputs:

define i32 @main() nounwind {
  ret i32 0
}


Your assumption is correct. The compiler implementation (correction pointed out by @Steve below) is free to optimise this code away to nothing (assuming it compiles at all), because it has no observable side-effects.


It's possible that the compiler will optimize it out. However, even if it doesn't, the added safety of an auto pointer will likely outweigh a few nanoseconds here or there. To be more C++-like you should even convert the macro declaration into an inline function that accomplishes the same thing. The compiler is able to optimize out inline functions like macros. For computational efficiency, concentrate on the data structures and algorithms you use. After you have the best data structures and algorithms, look at low level optimizations like this.

Edit

I looked at the code again. I'm having trouble thinking of a situation where the destructor would be optimized out. Best to assume it wouldn't be.


It can't optimise the delete away, that would change the semantics. (Although it could optimise the entire function to nothing.)

But there are better ways of doing this - RAII, scoped_ptr, shared_ptr, unique_ptr etc. And don't use macros unless you have to.


As you mentioned, std::auto_ptr doesn't take user provided deleter as an argument.
However, std::unique_ptr and std/boost::shared_ptr can take a deleter.
So, how about overloading operator new/delete and preparing your own deleter, and giving the deleter to the above smart pointers?
If those smart pointers aren't allowed, I'd suggest making your AutoPtr take an user provided deleter like the following:

void* operator new( size_t s, Application* app ) {
  return malloc( s );
}

void operator delete( void* p, Application* app ) throw() {
  free( p );
}

template< class T >
void delete_( T const* p, Application* app ) {
  p->~T();
  operator delete( (void*) p, app );
}

template< class T >
struct Deleter {
  Application *app;
  Deleter( Application* app ) : app( app ) {}
  void operator()( T const* p ) const { delete_( p, app ); }
};

template< class T, class D = Deleter<T> >
struct AutoPtr {
  T *ptr;
  D del;

  AutoPtr( T* ptr, D const& del ) : ptr( ptr ), del( del ) {}
  ~AutoPtr() { del( ptr ); }
};

int main() {
  Application *app = ...;
  AutoPtr<int> p( new( app ) int, Deleter<int>( app ) );
}


Not really a (direct) answer to your question, but take a look at boost::scoped_ptr as it already achieves what you are trying to do here.

e.g.

#include <boost/scoped_ptr.hpp>

int main()
{
    boost::scoped_ptr<char> a(new char);
    boost::scoped_ptr<char> b(new char);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜