在不提供名称的情况下声明类型

时间:2011-04-26 13:55:24

标签: c++ compiler-optimization

我在调试模式下测试了gcc上的一些代码,但不确定它是否适用于其他编译器 我的问题是任何编译器如何优化以下c ++代码(make_auto宏):

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(sizeof(char));
   make_auto(a);
   make_auto(b);
   return 0;
}

它总是会调用A的构造函数和析构函数吗?或者编译器会在任何情况下优化此代码并删除A(ptr)调用,因为它可以认为它不会被更多地使用。

UPD:

我知道boost和std :: auto_ptr。我有自己的内存管理器控制内存碎片,有助于避免内存泄漏。现在我想“教”我的内存管理器来创建auto_ptrs,就像它在boost和stl中一样。

UPD2:

这是完整的代码,我正在使用并且我认为工作正确:

    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");                
    }

输出:

构造函数调用 析构函数叫 构造函数调用 析构函数叫 Autoptrtest1通过了

所以它不正常,因为我认为(我没有检查析构函数调用)。但它像我之前所说的那样两次调用构造函数。 如何更改make_auto_ptr以自动声明auto-ptrs?

6 个答案:

答案 0 :(得分:7)

没有任何事情发生,因为你的代码格式不正确。 A(a);A(b);声明ab。由于a已经被声明,并且A在任何情况下都没有默认构造函数,编译器应该发出诊断信息。

如果您解决了这些问题,那么如果您使用的mallocfree是标准库的函数,则允许编译器优化这些问题,因为该代码确实没有可观察的一面效果。

优化编译器应该知道mallocfree的特殊含义,我不会惊讶地看到它优化了这一点。但无论出于何种原因,我还可以想象编译器不会优化它。它实际上取决于您的编译器及其使用的标志,但标准肯定允许它在这里进行优化。

以下是clang -O2 -emit-llvm -S main1.cpp -o -输出的代码:

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

答案 1 :(得分:4)

你的假设是正确的。 编译器实现(下面由@Steve指出的更正)可以自由地优化这个代码(假设它完全编译),因为它没有可观察到的副作用。

答案 2 :(得分:1)

编译器可能会优化它。然而,即使它没有,自动指针的附加安全性可能会在这里或那里超过几纳秒。要更多C ++ - 就像你甚至应该将宏声明转换为内联函数来完成同样的事情。编译器能够优化内联函数,如宏。为了提高计算效率,请专注于您使用的数据结构和算法。拥有最好的数据结构和算法后,请查看这样的低级优化。

修改

我再次查看了代码。我很难想到析构函数会被优化的情况。最好假设它不会。

答案 3 :(得分:0)

它无法优化删除,这将改变语义。 (虽然它可以将整个功能优化为零。)

但是有更好的方法可以做到这一点 - RAII,scoped_ptr,shared_ptr,unique_ptr等。除非必须,否则不要使用宏。

答案 4 :(得分:0)

如你所说, std::auto_ptr不会将用户提供的删除操作作为参数 然而, std::unique_ptrstd/boost::shared_ptr可以删除 那么,如何重载operator new / delete并准备自己的 删除,并给上述智能指针删除? 如果不允许这些智能指针,我建议你制作AutoPtr 使用用户提供的删除器,如下所示:

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 ) );
}

答案 5 :(得分:-1)

不是(直接)回答您的问题,但请查看boost::scoped_ptr,因为它已经实现了您在此处尝试的目标。

e.g。

#include <boost/scoped_ptr.hpp>

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