为什么 C++ 不支持函数返回数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5157439/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't C++ support functions returning arrays?
提问by Lockhead
Some languages enable you to just declare a function returning an array like a normal function, like Java:
某些语言使您可以像普通函数一样声明一个返回数组的函数,例如 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?
为什么 C++ 不支持类似的东西int[] funcarray(){}
?您可以返回一个数组,但是制作这样一个函数真的很麻烦。而且,我在某处听说字符串只是字符数组。因此,如果您可以在 C++ 中返回一个字符串,为什么不能返回一个数组呢?
回答by Doug Stephen
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
让我们首先考虑 C。在 C 语言中,“按引用传递”和“按值传递”有明显的区别。轻描淡写地说,C 中数组的名称实际上只是一个指针。出于所有意图和目的,差异(通常)归结为分配。编码
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,
将在堆栈上创建 4*n 字节的内存(在 32 位系统上),与进行声明的代码块的范围相关。反过来,
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:
将打印数字 4 因为构造 n
评估为 4(对不起,如果这是基本的,我只想涵盖所有基础)。这个 4 与你的程序的内存空间绝对没有关系或关系,它只是一个文字,所以一旦你离开了那个 4 有上下文的范围,你就失去了它。通过引用传递呢?在函数的上下文中按引用传递没有什么不同;您只需评估通过的构造。唯一的区别是在评估传递的“事物”之后,您将评估结果用作内存地址。我曾经有一个特别愤世嫉俗的 CS 讲师,他喜欢说没有通过引用传递这样的东西,只是传递聪明值的一种方式。真的,他是对的。所以现在我们从函数的角度考虑作用域。假设你可以有一个数组返回类型:
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:
这里的问题是 result 计算为数组的第 0 个元素的地址。但是,当您尝试从该函数的外部(通过返回值)访问该内存时,就会出现问题,因为您正在尝试访问不在您正在使用的范围内(函数调用的堆栈)的内存。所以我们解决这个问题的方法是使用标准的“通过引用传递”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.
我们仍然得到一个指向数组第 0 个元素的内存地址,但现在我们可以访问该内存。
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.
我的意思是什么?在 Java 中,通常会断言“一切都是按值传递”。这是真的。上面那个愤世嫉俗的讲师也对 Java 和 OOP 大体上说过:一切都只是一个指针。他也是对的。尽管 Java 中的所有内容实际上都是按值传递的,但几乎所有这些值实际上都是内存地址。因此,在 Java 中,该语言确实允许您返回数组或字符串,但它是通过将其转换为带有指针的版本来实现的。它还为您管理您的记忆。自动内存管理虽然有用,但效率不高。
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.
这将我们带到了 C++。C++ 被发明的全部原因是因为 Bjarne Stroustrup 在他的博士研究期间一直在试验 Simula(基本上是原始的 OOPL),并认为它在概念上非常棒,但他注意到它的表现相当糟糕。于是他开始研究所谓的 C with Classes,它被重命名为 C++。在这样做的过程中,他的目标是制作一种编程语言,该语言吸收了 Simula 的一些最佳功能,但仍保持强大和快速。他选择扩展 C 是因为它已经具有传奇般的性能,一个权衡是他选择不像其他 OOPL 那样大规模地实现自动内存管理或垃圾收集。从模板类之一返回数组是有效的,因为您正在使用一个类。但是如果你想返回一个 C 数组,你必须用C的方式来做。换句话说,C++ 确实支持以与 Java 完全相同的方式返回数组;它只是不为你做所有的工作。因为一个丹麦人认为它太慢了。
回答by CashCow
C++ does support it - well sort of:
C++ 确实支持它 - 很好:
vector< string> func()
{
vector<string> res;
res.push_back( "hello" );
res.push_back( "world" );
return res;
}
Even C sort-of supports it:
甚至 C 类也支持它:
struct somearray
{
struct somestruct d[50];
};
struct somearray func()
{
struct somearray res;
for( int i = 0; i < 50; ++i )
{
res.d[i] = whatever;
}
// fill them all in
return res;
}
A std::string
is a class but when you say a string you probably mean a literal. You can return a literal safely from a function but actually you could statically create any array and return it from a function. This would be thread-safe if it was a const (read-only) array which is the case with string literals.
Astd::string
是一个类,但是当您说字符串时,您可能指的是文字。您可以从函数安全地返回文字,但实际上您可以静态创建任何数组并从函数返回它。如果它是一个常量(只读)数组(字符串文字就是这种情况),那么这将是线程安全的。
The array you return would degrade to a pointer though, so you would not be able to work out its size just from its return.
但是,您返回的数组会降级为指针,因此您无法仅从其返回值中计算出其大小。
Returning an array, if it were possible, would have to be fixed length in the first place, given that the compiler needs to create the call stack, and then has the issue that arrays are not l-values so receiving it in the calling function would have to use a new variable with initialisation, which is impractical. Returning one may be impractical too for the same reason, atlhough they might have used a special notation for return values.
返回一个数组,如果可能的话,首先必须是固定长度的,因为编译器需要创建调用堆栈,然后有数组不是左值的问题,所以在调用函数中接收它必须使用带有初始化的新变量,这是不切实际的。出于同样的原因,返回一个也可能不切实际,尽管他们可能对返回值使用了特殊的表示法。
Remember in the early days of C all the variables had to be declared at the top of the function and you couldn't just declare at first use. Thus it was infeasible at the time.
请记住,在 C 的早期,所有变量都必须在函数顶部声明,并且您不能在第一次使用时就声明。因此在当时是行不通的。
They gave the workaround of putting the array into a struct and that is just how it now has to remain in C++ because it uses the same calling convention.
他们给出了将数组放入结构体的解决方法,这就是它现在必须保留在 C++ 中的方式,因为它使用相同的调用约定。
Note: In languages like Java, an array is a class. You create one with new. You can reassign them (they are l-values).
注意:在 Java 等语言中,数组是一个类。你用新创造一个。您可以重新分配它们(它们是左值)。
回答by David Rodríguez - dribeas
Arrays in C (and in C++ for backwards compatibility) have special semantics that differ from the rest of the types. In particular, while for the rest of the types, C only has pass-by-value semantics, in the case of arrays the effect of the pass-by-value syntax simulates pass-by-reference in a strange way:
C 中的数组(为了向后兼容而在 C++ 中)具有与其他类型不同的特殊语义。特别是,对于其余的类型,C 只有值传递语义,在数组的情况下,值传递语法的效果以一种奇怪的方式模拟了引用传递:
In a function signature, an argument of type array of N elements of type Tgets converted to pointer to T. In a function call passing an array as argument to a function will decaythe array to a pointer to the first element, and that pointer is copied into the function.
在函数签名中,类型为 T 的 N 个元素的数组类型的参数被转换为指向 T 的指针。在将数组作为参数传递给函数的函数调用中,会将数组衰减为指向第一个元素的指针,并将该指针复制到函数中。
Because of this particular treatment for arrays --they cannot be passed by value--, they cannot be returned by value either. In C you can return a pointer, and in C++ you can also return a reference, but the array itself cannot be allocated in the stack.
由于对数组的这种特殊处理——它们不能按值传递——,它们也不能按值返回。在 C 中你可以返回一个指针,在 C++ 中你也可以返回一个引用,但数组本身不能在堆栈中分配。
If you think of it, this is not different from the language that you are using in the question, as the array is dynamically allocated and you are only returning a pointer/reference to it.
如果您考虑一下,这与您在问题中使用的语言没有什么不同,因为数组是动态分配的,您只返回指向它的指针/引用。
The C++ language, on the other hand, enables different solutions to that particular problem, like using std::vector
in the current standard (contents are dynamically allocated) or std::array
in the upcoming standard (contents can be allocated in the stack, but it might have a greater cost, as each element will have to be copied in those cases where the copy cannot be elided by the compiler). In fact, you can use the same type of approach with the current standard by using off-the-shelf libraries like boost::array
.
另一方面,C++ 语言为该特定问题提供了不同的解决方案,例如std::vector
在当前标准中使用(内容是动态分配的)或std::array
在即将到来的标准中使用(内容可以在堆栈中分配,但它可能有更大的成本,因为在编译器无法省略副本的情况下,必须复制每个元素)。事实上,您可以通过使用现成的库(如boost::array
.
回答by Orbit
"You can't return array from the function because that array would be declared inside the function, and its location would then be the stack frame. However, stack frame is erased when function exits. Functions must copy return value from stack frame to return location, and that's not possible with arrays."
“您不能从函数中返回数组,因为该数组将在函数内部声明,然后其位置将是堆栈帧。但是,当函数退出时,堆栈帧会被擦除。函数必须从堆栈帧复制返回值才能返回位置,而这在数组中是不可能的。”
From a discussion here:
从这里的讨论:
http://forum.codecall.net/c-c/32457-function-return-array-c.html
http://forum.codecall.net/cc/32457-function-return-array-c.html
回答by AProgrammer
Other have said that in C++, one use vector<> instead of the arrays inherited from C.
其他人说在 C++ 中,使用 vector<> 而不是从 C 继承的数组。
So why C++ doesn't allows to returns C arrays? Because C doesn't.
那么为什么 C++ 不允许返回 C 数组呢?因为C没有。
Why C doesn't? Because C evolved from B, a untyped language in which returning an array doesn't make sense at all. When adding types to B, it would have been meaningful to make it possible to return an array but that wasn't done in order to keep some B idioms valid and ease the conversion of programs from B to C. And since then, the possibility of making C arrays more usable as always been refused (and even more, not even considered) as it would break too much existing code.
为什么 C 没有?因为 C 是从 B 演变而来的,所以一种返回数组的无类型语言根本没有意义。在向 B 添加类型时,让返回数组成为可能是有意义的,但这样做并不是为了保持某些 B 习语有效并简化程序从 B 到 C 的转换。从那时起,可能性使 C 数组更有用的做法一直被拒绝(甚至更多,甚至没有考虑过),因为它会破坏太多现有的代码。
回答by Jordi
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.
或者您可以只使用 std 命名空间中的容器之一,例如 std::vector。
回答by vbence
"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++ 不支持类似的东西”:因为它没有任何意义。在 JAVA 或 PHP 等基于引用的语言中,内存管理基于垃圾收集。没有引用的内存部分(程序中没有变量再指向它)会自动释放。在这种情况下,您可以分配内存,并无忧无虑地传递引用。
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 ownershipof memory blocks. You have to know if the pointer you go is yours to free at any time (in fact you shoudfree it after use), or you have a pointer to a shared portion of memory, which is an absolute no-no to free.
C++代码会被翻译成机器码,里面没有定义GC。所以在 C 和 C++ 中有强烈的内存块所有权意识。你必须知道你去的指针是否是你可以随时释放的(实际上你应该在使用后释放它),或者你有一个指向共享内存部分的指针,这是绝对禁止释放的。
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.
在这种环境中,每次传入和传出函数时都创建数组的无限副本,您将一无所获。用类似 c 的语言管理数据数组要复杂得多。没有一刀切的解决方案,您需要知道何时释放内存。
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?
函数返回的数组是否总是一个副本(你的自由)还是你必须制作它们的副本?通过将一个数组插入一个指向数组的指针,你会赢吗?
回答by David Thornley
Return a std::vector<>
instead of an array. In general, arrays do not work well with C++, and should generally be avoided.
返回一个std::vector<>
而不是一个数组。通常,数组在 C++ 中不能很好地工作,通常应该避免使用。
Also, the string
datatype is not just an array of characters, although a "quoted string" is. The string
manages an array of characters, and you can get access to it with .c_str()
, but there's more to a string
than that.
此外,string
数据类型不仅仅是一个字符数组,尽管“带引号的字符串”是。Thestring
管理一个字符数组,您可以使用 来访问它.c_str()
,但是 a 的作用string
远不止于此。
回答by sgokhales
Check out here. Really helpful.
看看这里。真的很有帮助。