Why doesn't C++ support functions returning ar

2019-01-02 20:25发布

Some languages enable you to just declare a function returning an array like a normal function, like Java:

public String[] funcarray() {
   String[] test = new String[]{"hi", "hello"};
   return test;
}

Why doesn't C++ support something like int[] funcarray(){} ? You can return an array, but it's a real hassle to make such a function. And also, I heard somewhere that strings are just arrays of char. So if you can return a string in C++, why not an array?

9条回答
浮光初槿花落
2楼-- · 2019-01-02 21:07

I'd wager a guess that to be concise, it was simply a design decision. More specifically, if you really want to know why, you need to work from the ground up.

Let's think about C first. In the C language, there is a clear distinction between "pass by reference" and "pass by value". To treat it lightly, the name of an array in C is really just a pointer. For all intents and purposes, the difference (generally) comes down to allocation. The code

int array[n];

would create 4*n bytes of memory (on a 32 bit system) on the stack correlating to the scope of whichever code block makes the declaration. In turn,

int* array = (int*) malloc(sizeof(int)*n);

would create the same amount memory, but on the heap. In this case, what is in that memory isn't tied to the scope, only the reference TO the memory is limited by the scope. Here's where pass by value and pass by reference come in. Passing by value, as you probably know, means that when something is passed in to or returned from a function, the "thing" that gets passed is the result of evaluating the variable. In other words,

int n = 4;
printf("%d", n);

will print the number 4 because the construct n evaluates to 4 (sorry if this is elementary, I just want to cover all the bases). This 4 has absolutely no bearing or relationship to the memory space of your program, it's just a literal, and so once you leave the scope in which that 4 has context, you lose it. What about pass by reference? Passing by reference is no different in the context of a function; you simply evaluate the construct that gets passed. The only difference is that after evaluating the passed "thing", you use the result of the evaluation as a memory address. I once had a particular cynical CS instructor who loved to state that there is no such thing as passing by reference, just a way to pass clever values. Really, he's right. So now we think about scope in terms of a function. Pretend that you can have an array return type:

int[] foo(args){
    result[n];
    // Some code
    return result;
}

The problem here is that result evaluates to the address of the 0th element of the array. But when you attempt to access this memory from outside of this function (via the return value), you have a problem because you are attempting to access memory that is not in the scope with which you are working (the function call's stack). So the way we get around this is with the standard "pass by reference" jiggery-pokery:

int* foo(args){
    int* result = (int*) malloc(sizeof(int)*n));
    // Some code
    return result;
}

We still get a memory address pointing to the 0th element of the Array, but now we have access to that memory.

What's my point? In Java, it is common to assert that "everything is pass by value". This is true. The same cynical instructor from above also had this to say about Java and OOP in general: Everything is just a pointer. And he's also right. While everything in Java is in fact pass by value, almost all of those values are actually memory addresses. So in Java, the language does let you return an array or a String, but it does so by turning it in to the version with pointers for you. It also manages your memory for you. And automatic memory management, while helpful, is not efficient.

This brings us to C++. The whole reason C++ was invented was because Bjarne Stroustrup had been experimenting with Simula (basically the original OOPL) during his PhD work, and thought it was fantastic conceptually, but he noticed that it performed rather terribly. And so he began working on what was called C with Classes, which got renamed to C++. In doing so, his goal was to make a programming language that took SOME of the best features from Simula but remained powerful and fast. He chose to extend C due to its already legendary performance, and one tradeoff was that he chose to not implement automatic memory management or garbage collecting on such a large scale like other OOPL's. Returning an array from one of the template classes works because, well, you're using a class. But if you want to return a C array, you have to do it the C way. In other words, C++ does support returning an array EXACTLY the same way that Java does; it just doesn't do all of the work for you. Because a Danish dude thought it'd be too slow.

查看更多
牵手、夕阳
3楼-- · 2019-01-02 21:08

You can return a pointer to the array. Just be careful about releasing the memory later.

public std::string* funcarray() {
    std::string* test = new std::string[2];
    test[0] = "hi";
    test[1] = "hello";
    return test;
}

// somewhere else:
std::string* arr = funcarray();
std::cout << arr[0] << " MisterSir" << std::endl;
delete[] arr;

Or you can just use one of the containers in the std namespace, like std::vector.

查看更多
还给你的自由
4楼-- · 2019-01-02 21:09

"Why doesn't C++ support something like": Because it would not make any sense. In reference-based languages like JAVA or PHP, memory management is based on garbage collection. The portions of memory which have no references (no variable in your program points to it any more) is automatically freed. In this context you can allocate memory, and pass the reference around carefreely.

C++ code will be translated to machine code, and there is no GC defined in it. So in C and C++ there is a strong sense of ownership of memory blocks. You have to know if the pointer you go is yours to free at any time (in fact you shoud free it after use), or you have a pointer to a shared portion of memory, which is an absolute no-no to free.

In this environment you would win nothing with cretaing endless copies of an array every time it passes to and from a function. It is amuch more complex task to manage your arrays of data in c-like languages. There is no one-size-fits-all solution, and you need to know when to free memory.

Would an array returned by a function always be a copy (yours to free) or you have to make copies of them? Whet would you win by getting an array insted of a pointer to an array?

查看更多
登录 后发表回答