-3

我认为我的问题听起来很愚蠢,欢迎对我投反对票。如果您在 C++ 中实现需要返回指针的方法,这样做是否安全?如果不是,为什么?

4

4 回答 4

0

是的。我假设您的意思是“分配并返回”一个指针。

通常具有初始化函数,它分配指向某种类型的对象的指针,然后初始化对象本身。然后由程序的不同部分来释放内存。

于 2013-10-29T04:45:42.747 回答
0

那么它总是取决于你在做什么。指针只是一个内存地址,因此它类似于简单地返回一个整数。您应该对指针以及如何正确实现它们进行更多研究

于 2013-10-29T04:46:04.737 回答
0

我觉得这个问题可能很快就会结束,但无论如何我都会尝试回答。

是的,只要你小心,它是“安全的”。事实上,这是一种非常常见的做事方式,尤其是在与 C API 交互时。话虽如此,如果可以,最好避免这样做,因为 C++ 通常提供更好的替代方案。

为什么要避免它?首先,假设您有一个如下所示的方法:

MyStruct* get_data();

返回值是指向单个实例的指针MyStruct,还是数组的开头?你需要free()返回的指针吗?或者也许你需要使用delete?返回值可以是NULL,如果是,会发生什么?如果不查看文档,您将无法了解这些内容。而且编译器也无法知道,因此它无法以任何方式帮助您。

更好的选择:

如果要返回值数组,请使用 a std::array(如果大小在编译时固定)或 a std::vector(如果直到运行时才知道大小)。

如果您试图避免复制大型结构,则返回一个引用,或者如果可能的话返回一个 const 引用。这样调用者就知道他们不会收到NULL值。

如果你真的需要返回一个指针,而不是考虑使用智能指针——这将帮助你解决所有权问题。例如,std::shared_ptr使用引用计数,并std::unique_ptr确保给定指针只有一个所有者。

于 2013-10-29T04:56:37.010 回答
0

不是一个简单的问题。例如:返回指针的最佳方式

理想情况下,您应该尽量避免返回带有副作用或义务的值。

// This may be ok, it implies no burden on the user.
Manager* GetManager();
// But what if the user decides to call delete on the value you return?

// This is not unusual in C code, but carries a hidden contract:
// I allocate - you free.
const char* GetFilename(int fd)
{
    char* filename = malloc(256);
    sprintf(filename, "/tmp/tmpfile.%d", fd);
    return filename;
}

C++ 是关于封装和抽象的。您可以通过封装要返回的指针来编写与消费者的合同。这里的想法是,不是公开一个指针,而是公开一个负责指针所有权的对象。事实上,该语言的最新版本已经使用 std::unique_ptr、std::shared_ptr 和 std::weak_ptr 为您做到这一点。

但一个粗略、简单的 RAII 示例可能是:

class StrDupPtr
{
    char* m_alloc;
public:
    StrDupPtr(const char* src)
        : m_alloc(strdup(src))
    {}

    ~StrDupPtr()
    {
        free(m_alloc);
    }

    operator const char* () const { return m_alloc; }

    // etc.
};

您仍然在此处返回一个指针,但您已将其封装在管理合同中,并减轻了最终用户管理资源的负担。

你不能总是避免它,当你不得不这样做时,是的,它可能很危险。

int* AllocateMeSomeMemory()
{
    int* memory = malloc(4 * sizeof(int));
    // here, have four ints.
    return memory;
}

int main() {
    int* memory = AllocateMeSomeMemory();
    memory[42] = 0xDeath; // yeah, it's not a valid hex number, but that's not really the problem.
}

指针的另一个常见问题是无法知道有多少人拥有指针。这是一个人为的例子:

void transferItem(userid_t user1, userid_t user2, itemid_t item) {
    Account* a1 = GetAccount(user1);
    Account* a2 = GetAccount(user2);

    if (a1 != a2) {
        transferItemInternal(a1, a2, item);
    }

    delete a2;
    delete a1;  // Sorry Dave, I can't do that. How about a nice game of CRASH?
}

通常,a2 和 a1 会有所不同,但是当它们不同时...

另一个常见的指针失败模式是异步回调:

// ask the database for user details, call OnLoginResult with userObj when we're done.
void login(int socket, userid_t userId, passwordhash_t pass) {
    User* userObj = GetUserObj(userId, socket);
    Query* query = Database()->NewQuery("SELECT * FROM user WHERE id = ? AND password = ?", userId, pass);
    Database()->Queue(query, OnLoginResult, userObj);
}

void OnDisconnect(int socket, int reason) {
    User* userObj = GetUserBySocket(socket);
    if (userObj) {
        UnregisterUserObj(userObj);
        delete userObj;
    }
}

void OnLoginResult(void* param) {
    User* userObj = static_cast<UserObj*>(param);
    // all well and good unless the user disconnected while waiting.
    ...
}
于 2013-10-29T06:26:16.173 回答