C ++:如何防止函数接受一个在线分配的指针? [英] C++: How do I prevent a function from accepting a pointer that is allocated in-line?

查看:281
本文介绍了C ++:如何防止函数接受一个在线分配的指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

无法弄清楚如何准确地说出问题,因此下面是一个例子:

Couldn't figure out how to word the question accurately, so here's an example:

给定此函数原型:

void Foo(myClass* bar);

我想阻止此用法:

Foo(new myClass());

,而需要先前创建的对象:

and instead require a previously created object:

myClass* bar = NULL;
bar = new myClass();
Foo(bar);

myClass bar;
Foo(&bar);

感谢。

这里有一个澄清的例子:

Here's a clarified example:


void Mouse::SetImage(BITMAP* image, int focusX, int focusY) {
    if(_image) {
        set_mouse_sprite(NULL);
        set_mouse_sprite_focus(0, 0);
        show_mouse(NULL);
        destroy_bitmap(_image);
        _image = NULL;
    }
    if(image) {
        _image = create_bitmap(image->w, image->h);
        clear_bitmap(_image);
        blit(image, _image, 0, 0, 0, 0, image->w, image->h);
    }
    if(image == NULL) {
        focusX = 0;
        focusY = 0;
    }
    _focusX = focusX;
    _focusY = focusY;
    _dirtyImage = true;
}

用户传递的任何图像都会复制到对象的图像。

Whatever image the user passes in gets copied to the object's image.

如果我复制后传递的图像被释放,并且该图像在程序中的其他地方使用,那么它会导致程序崩溃,访问冲突。

If I deallocate the passed in image after copying it and the image is used elsewhere in the program it will crash the program with an access violation.

如果他们在线分配存储,而我不释放它,就会发生内存泄漏。

If they allocate the storage in-line and I don't deallocated it, a memory leak occurs. The problem is compounded if they call the SetImage method multiple times over the course of the running program.

如果在运行程序过程中多次调用SetImage方法,问题会复杂化。对于使用替代库或Allegro库本身的注释将被忽略,我已经知道这是可怕的。我没有选择。

Comments about using alternative libraries or on the Allegro Library itself will be ignored, I already know it's horrible. I don't have a choice.

推荐答案

您的设计需要做出选择。取得所有权并删除它,或不占有所有权。 无论哪种方式,由用户知道如何使用你的函数。他们需要知道你的函数会破坏图像(也许根据需要传递自己的副本),或者他们需要足够聪明地管理自己的资源。

Your design needs to make a choice. Either take ownership and delete it, or don't take ownership. Either way, it's up to the user to know how to use your function. They either need to know that your function will destroy the image (and maybe pass their own copy as needed), or they need to be smart enough to manage their own resources.

通常,你不想偷走所有权,只是删除它。所以我不会删除任何东西。如果有人是愚蠢的,失去了删除他们通过的图像的能力,这不是这个功能问题。换句话说,你应该尝试保护Murphy,但忘记保护Machiavelli。

Typically, you don't want to steal ownership away just to delete it. So I would not delete anything. If someone is silly enough to lose the ability to delete the image they pass, that's not this functions problem. In other words, you should try to protect against Murphy, but forget about protecting against Machiavelli.

这就是说,原始指针使用是坏的!可怜的C ++代码由手动资源管理和资源问题标记。你应该有一个图像周围的包装,将删除析构函数中的图像。这样,即使抛出异常,您也可以永远泄漏。为它提供一个 reset()方法,它会丢弃旧的图片资源并获取新的图片资源。

That said, raw pointer use is bad! Poor C++ code is marked by manual resource management and resource issues. You should have a wrapper around an image, that will delete the image in the destructor. That way you can never leak, even if an exception is thrown. Provide it with a reset() method which discards it's old image resource and gets a new one.

像您想要共享所有权,因此您将需要一个引用计数资源包装器。然后解决问题:如果有人执行内联分配,它将被放入共享指针,然后在完成后自动删除。 (更好的是有一个显式构造函数,所以有人必须知道他们会共享资源。)

It sounds like you want shared ownership, so you'll want a reference counted resource wrapper. The issue is then solved: if someone does an "inline" allocation, it'll be put into the shared pointer and then deleted automatically when it's done. (And even better is to have an explicit constructor so someone has to know they'll be sharing the resource.)

这是通过一个名为 shared_ptr 的智能指针完成的。 Boost 有一个,TR1有一个,而C ++ 0x有一个。只是给它一个自定义删除(释放图像),你从来不担心资源管理了。

This is done in a smart pointer called shared_ptr. Boost has one, TR1 has one, and C++0x has one. Just give it a custom deleted (one that frees the image), and you never worry about resource management again.

这应该使用所有资源。这里的概念是范围限制资源管理(SBRM);通过利用自动(堆栈)变量的生存规则来自动管理资源。这是已知的原因,因为它是原始的,但更丑的名称资源获取是初始化< (RAII)。对这一领域进行一些研究,你会发现你的代码更容易和更干净。

This should be done with all resources. The concept here is Scoped-bound Resource Management (SBRM); that a resource is managed automatically by taking advantage of the lifetime rules of automatic (stack) variables. It's known alos as it's original but uglier name Resource-Acquisition Is Initialization (RAII). Do some research into this area and you'll find your code is easier and cleaner.

参数的类型。您可以将其更改为:

It cannot be done without changing the type of the parameter. You could change it to:

void Foo(myClass*& bar);

因为非const引用只能绑定到一个左值:

Because a non-const reference can only be bound to an lvalue:

void foo(int*&);

int main(void)
{
    int *i = 0;
    int j;

    foo(i); // well-formed
    foo(&j); // ill-formed
    foo(new int); // ill-formed
}

但是,这不允许使用左值的地址。你当然可以这样做:

However, this disallows taking the address of an lvalue. You can of course do the simple:

int main(void)
{
    int j;
    int* pj = &j;
    foo(pj); // well-formed
}

但我不知道你为什么要这样做。

And it works. But I don't know why you'd want to do any of this.

上述解决方案可以让你修改参数(因为它是引用)。如果你想在函数中强制执行const,你可以使用这样的实用程序:

The above solution would allow you to modify the argument (because it's a reference). If you wanted to enforce const within the function, you could make a utility like this:

template <typename T>
class require_lvalue
{
public:
    require_lvalue(T& pX) :
    mX(pX)
    {}

    const T& get(void) const
    {
        return mX;
    }

    operator const T&(void) const
    {
        return get();
    }

private:
    // non-copy-assignable
    require_lvalue& operator=(const require_lvalue&);

    const T& mX;
};

void foo(require_lvalue<int*>);

相同的结果,除非在函数中有一个const引用。

Same result, except you have a const-reference within the function.

请注意,MSVC有一个错误,并接受:

Note that MSVC has a bug, and accepts this:

foo(new int);

在这两种情况下,即使不应该。 (但它不接受 new int()

in both cases, even though it shouldn't. (It does not accept new int(), however.)

这篇关于C ++:如何防止函数接受一个在线分配的指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆