about "delete" and "delete []"

Started by
34 comments, last by xiajia 11 years, 2 months ago

thanks for Brother Bob,Cornstalks and rip-off.These recommendations so refreshing for me.I should solve the problem instead of ducking the issue about double delete.

you can and should provide it as a regular free function rather than a macro:

Not "macro higher efficiency than function"?

Advertisement
Not "macro higher efficiency than function"?

Not really, no. Compilers these days are incredibly smart. They can inline functions if needed (especially little tiny, templated ones like that), just as if it were a macro. However, sometimes if you inline too many things, you just end up bloating your code (which can actually slow you down). By making it a function, you are letting the compiler decide if its better to inline the function or not to (most of the time, for a tiny function like that, it'll inline it). The compiler knows the target system better than you, and can make smart optimization decisions. If you use a macro, you are forcing inlining, which may not be optimal. So from an efficiency perspective, just use a function.

However, there's another negative side of using macros. Macros do not respect scoping rules at all, whereas functions do. You can put a function in a namespace, and if you scope things right, you can have multiple functions, all with the same name (this is important so the code you write doesn't conflict with or "override" the code someone else writes, even if you both have a function named "dotProduct" for example). Macros don't do this.

And again, another negative of using macros: how their arguments are evaluated. Try the following with the macro, and compare it with a function:

// I know you're code isn't doing something like this, // but it shows another drawback of macros vs functions // Go to http://ideone.com/YWAsoX for the results #include <iostream> #define MACRO_ABS(p) ((p) < 0 ? -(p) : (p)) template <typename T> T function_abs(T p) { return p < 0 ? -p : p; } int main() { int i = -100;
std::cout << "macro: " << MACRO_ABS(i++) << std::endl; std::cout << "i: " << i << std::endl; i = -100;
std::cout << "function: " << function_abs(i++) << std::endl;

std::cout << "i: " << i << std::endl;
}
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

template<typename T>
void XDELETE(T *&p)
{
    delete p;
    p = NULL;
}

template<class T> class tempClassA;
template<class T> class tempClass
{
private:
    friend tempClassA<T>;
    T * m_p;
    tempClass()
        :m_p(NULL)
    {
    }
    ~tempClass()
    {
        XDELETE(m_p);
    }
};
template<class T> class tempClassA
{
public:
    tempClassA()
        :m_a(new tempClass<T>())
    {
    }
    ~tempClassA()
    {
         XDELETE(m_a);
    }
private:
    tempClass<T> * m_a;
};

int main()
{
    tempClassA<int> a;
    return 0;
}

compile error. sad.png

compile error. sad.png

What compiler error? If you can't find the time to report the problem correctly and completely, I can't find the time to help you.

What error and where is it?

compiling with VS2005,

error C2248:'tempClass<T>::~tempClass' : cannot access private member declared in class 'tempClass<T>'

line 4: delete p;

Do we have to guess the error? Or the intended behaviour?

Presumably from your "friend" declaration, you want "tempClass" to only be created and destroyed by "tempClassA".

You could clarify this using better naming (these two class names are confusingly similar):

template<typename T>
void XDELETE(T *&p)
{
delete p;
p = nullptr;
}
template<class T> class Example;
template<class T> class MostlyPrivate
{
private:
friend class Example<T>;
T * m_p;
MostlyPrivate()
:m_p(nullptr)
{
}
~MostlyPrivate()
{
XDELETE(m_p);
}
};
template<class T> class Example
{
public:
Example()
:m_a(new MostlyPrivate<T>())
{
}
~Example()
{
XDELETE(m_a);
}
private:
MostlyPrivate<T> * m_a;
};
int main()
{
Example<int> a;
return 0;
}

The compiler error (having corrected some of the more trivial errors) says:

$ g++ test.cpp -std=c++0x
test.cpp: In function ‘void XDELETE(T*&) [with T = MostlyPrivate<int>]’:
test.cpp:38:10: instantiated from ‘Example<T>::~Example() [with T = int]’
test.cpp:47:18: instantiated from here
test.cpp:23:5: error: ‘MostlyPrivate<T>::~MostlyPrivate() [with T = int]’ is private
test.cpp:4:5: error: within this context

[/quote]

Highlighting the most relevant lines:

$ g++ test.cpp -std=c++0x
test.cpp: In function ‘void XDELETE(T*&) [with T = MostlyPrivate<int>]’:
test.cpp:38:10: instantiated from ‘Example<T>::~Example() [with T = int]’
test.cpp:47:18: instantiated from here
test.cpp:23:5: error: ‘MostlyPrivate<T>::~MostlyPrivate() [with T = int]’ is private
test.cpp:4:5: error: within this context

[/quote]

Essentially, the problem is that XDELETE is trying to call a private destructor. Even though "Example" is a friend, and the call to XDELETE is coming from "Example", that does not confer friendship onto XDELETE. Note this is an interesting case of where the macro version could be considered to be "bypassing" language rules.

One solution is to add XDELETE as a friend too. Another is to consider making the destructor public - perhaps making the constructor private is enough to prevent whatever mishaps you're worried about?

The most obvious solution is to use delete, not XDELETE, because you are in a destructor and thus it would be undefined behaviour for any code to touch this pointer again anyway.

Actually, XDELETE is an abomination. In correctly written code, setting the pointer to 0 will never matter, so it's a wasted operation. In poorly written code, it will sometimes help (if someone tries to access a member through the pointer after it has been deleted) and sometimes hurt (if someone tries to delete the pointer again, which is a problem that will now be masked).

You are also missing a semicolon after the tempClassA block, and the word `class' after `friend'.

Why do you feel the need to call `new' at all? I rarely do it. Your members should be objects, not pointer to objects, unless you have a good reason ("I used to be a Java programmer and feel the need to write `new' all over the place" is not a good reason).

I think "make the destructor public" is better than "add XDELETE as a friend to class MostlyPrivate",biggrin.png

about the semicolon after the tempClassA,it is a small accident.happy.png the main function is added later.The compiler will not complain if not coupled.

This topic is closed to new replies.

Advertisement