在C ++中返回一个指针

时间:2013-10-29 04:41:35

标签: c++

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

4 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我觉得这个问题很快就会被关闭,但无论如何我都会尝试回答。

是的,只要你小心,这是“安全的”。事实上,这是一种非常常见的做事方式,特别是在您与C API接口的情况下。话虽如此,如果可以的话,最好避免这样做,因为C ++通常会提供更好的替代方案。

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

MyStruct* get_data();

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

更好的选择:

如果要返回值数组,请使用std::array(如果大小在编译时修复)或std::vector(如果大小未知,则运行 - 时间)。

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

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

答案 3 :(得分:0)

不是一个简单的问题。例如:Best way of returning a pointer

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

// 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.
    ...
}