C++ 为struct动态分配内存
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9397288/
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
Dynamically allocate memory for struct
提问by sircrisp
I am taking a C++ class and have a assignment which requires me to dynamically allocate memory for a struct. I don't recall ever going over this in class and we only briefly touched on the new
operator before going on to classes. Now I have to
我正在学习一个 C++ 类,并且有一个任务需要我为结构动态分配内存。我不记得曾经在课堂上讨论过这个,我们在上课new
之前只是简单地接触过 操作符。现在我必须
"Dynamically allocate a student and then prompts the user for student's first name, a last name, and A - number(ID number). "
“动态分配一个学生,然后提示用户输入学生的名字、姓氏和A-number(ID号)。”
my struct is written like
我的结构是这样写的
struct Student
{
string firstName, lastName, aNumber;
double GPA;
};
I tried Student student1 = new Student;
but that doesn't work and I'm unsure as how I do this dynamically with a struct.
我试过了,Student student1 = new Student;
但这不起作用,我不确定我是如何用结构动态地做到这一点的。
回答by parapura rajkumar
Change you definition to
将您的定义更改为
struct Student
{
string firstName, lastName, aNumber;
double GPA;
};
Notice I have changed the placement of the struct keyword
请注意,我更改了 struct 关键字的位置
and you have to do Student* student1 = new Student
instead.
而你必须这样做Student* student1 = new Student
。
When you dynamically allocated memory for a struct you get a pointer to a struct.
当您为结构动态分配内存时,您会得到一个指向结构的指针。
Once you are done with the Studentyou also have to remember to to release the dynamically allocated memory by doing a delete student1
. You can use a std::shared_ptrto manage dynamically allocated memory automatically.
完成Student 后,您还必须记住通过执行delete student1
. 您可以使用std::shared_ptr自动管理动态分配的内存。
回答by Puppy
This should be what you need:
这应该是你需要的:
std::unique_ptr<Student> x(new Student);
回答by Cheers and hth. - Alf
"Dynamically allocate a student and then prompts the user for student's first name, a last name, and A - number(ID number). "
“动态分配一个学生,然后提示用户输入学生的名字、姓氏和A-number(ID号)。”
This assignment requires you to have a not completely initialized Student
object around until you can update it with the information provided by the user. That is a very bad idea in general, because the mere possibility of having a not completely initialized object (e.g. in this case lacking a proper id value) makes the code using that object more complex because it has to check whether, for example, there is a proper id value. And that complexity for proper use, plus failures to recognize that the complexity is needed for proper use, attracts bugs like mad – ungood.
此分配要求您有一个未完全初始化的Student
对象,直到您可以使用用户提供的信息对其进行更新。一般来说,这是一个非常糟糕的主意,因为仅仅有一个未完全初始化的对象(例如,在这种情况下缺少正确的 id 值)的可能性会使使用该对象的代码变得更加复杂,因为它必须检查是否存在,例如是一个正确的 id 值。而正确使用的复杂性,加上未能认识到正确使用需要复杂性,会吸引像疯子这样的错误 - 不好。
That is why C++, extending C, provided a very strong couplingbetween allocation and initialization. With a C++ new
expression you get either botha successful allocation and a successful complete initialization, or else neither (it cleans up on failure). That is what the question should better teach!
这就是为什么扩展 C 的 C++在分配和初始化之间提供了非常强的耦合。对于C ++new
表达式你要么都成功的分配和成功完成初始化,否则没有(它失败清理)。这就是问题应该更好地教导的!
So instead of the given question quoted above, I'm going to teach you acceptable C++ practice (although using new
is generally to be avoided), which means answering this modified question:
因此,代替上面引用的给定问题,我将教您可接受的 C++ 实践(尽管new
通常要避免使用),这意味着回答这个修改后的问题:
Prompt the user for student's first name, a last name, and A - number(ID number), and then dynamically allocate a
Student
object with these values.
提示用户输入学生的名字、姓氏和 A - number(ID 号),然后
Student
使用这些值动态分配一个对象。
OK, here goes:
好的,这里是:
// The Dynamic Student, version 1.
// "Prompt the user for student's first name, a last name, and A - number
// (ID), and then dynamically allocate a `Student` object with these values."
#include <assert.h> // assert
#include <iostream> // std::cout,std::endl
#include <string> // std::string
#include <sstream> // std::istringstream
#include <stdexcept> // std::exception, std::runtime_error
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#define CPP_NO_COPYING_OF( Clazz ) \
Clazz( Clazz const& ); \
Clazz& operator=( Clazz const& )
namespace cpp {
using namespace std;
bool hopefully( bool const c ) { return c; }
bool throwX( string const& s ) { throw runtime_error( s ); }
string lineFromInput()
{
string result;
getline( cin, result )
|| throwX( "lineFromInput: std::getline failed (EOF?)" );
return result;
}
string lineFromInput( string const& prompt )
{
cout << prompt;
return lineFromInput();
}
int intFromInput( string const& prompt )
{
istringstream stream( lineFromInput( prompt ) );
int result;
stream >> result
|| throwX( "intFromInput: input line was not a valid number spec" );
return result;
}
} // namespace cpp
namespace blah {
using namespace std;
using namespace cpp;
struct Student
{
CPP_NO_COPYING_OF( Student );
int const id;
string const firstName;
string const lastName;
Student(
int const _id,
string const _firstName,
string const _lastName
)
: id( _id ), firstName( _firstName ), lastName( _lastName )
{}
};
Student* studentFromInput()
{
cout << "It's -- the Dynamic Student program!" << endl;
string const firstName = lineFromInput( "First name, please? " );
hopefully( firstName != "" )
|| throwX( "Sorry, the first name can't be nothing." );
string const lastName = lineFromInput( "Last name, please? " );
hopefully( lastName != "" )
|| throwX( "Sorry, the last name can't be nothing." );
int const id = intFromInput( "And the student id is...? " );
hopefully( id > 0 )
|| throwX( "Sorry, the id can't be negative or zero." );
return new Student( id, firstName, lastName );
}
} // namespace blah
void cppMain()
{
using namespace blah;
Student const* const pStudent = studentFromInput();
try
{
// Use the student object, e.g.
cout
<< "The student is "
<< pStudent->firstName << " " << pStudent->lastName
<< ", with id " << pStudent->id << "."
<< endl;
// Then:
delete pStudent;
}
catch( std::exception const& )
{
delete pStudent;
throw; // Rethrows the exception.
}
}
int main()
{
using namespace std;
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
For each executed new
expression (which does allocation and initialization) there should ideally be a corresponding execution of a delete
expression, which cleans up and deallocates the memory block so that it can be reused. And the delete
expression should ideally be executed even if something fails and throws an exception. Hence the try
and catch
.
对于每个执行的new
表达式(执行分配和初始化),理想情况下应该有一个相应的delete
表达式执行,它清理和释放内存块以便可以重用。delete
理想情况下,即使某些事情失败并抛出异常,也应该执行该表达式。因此try
和catch
。
However, coding it like that is error prone and verbose.
但是,像这样编码很容易出错且冗长。
Instead, in more idiomatic C++ programming one will use a smart pointer, an object that holds a pointer and provides pointer operations (so it looks like it isa pointer), and whose destructor automatically executes a delete
expression when the pointer is no longer used. The C++ standard library has several such smart pointer classes. As a general rule, use the most restrictive smart pointer that you can, because it has least overhead and will most likely support conversion to more general smart pointers, while the opposite is much less likely, downright unlikely.
相反,在更惯用的C ++编程一个将使用一个智能指针,保存一个指针,并提供指针操作(所以它看起来像一个对象是一个指针),其析构函数自动执行一个delete
当指针不再使用的表达。C++ 标准库有几个这样的智能指针类。作为一般规则,尽可能使用限制性最强的智能指针,因为它的开销最小,并且很可能支持转换为更通用的智能指针,而相反的可能性要小得多,完全不可能。
So in this case, you can use e.g. C++11 std::unique_ptr
or if your compiler is old, C++03 std::auto_ptr
, both from the <memory>
header:
所以在这种情况下,你可以使用例如 C++11std::unique_ptr
或者如果你的编译器是旧的, C++03 std::auto_ptr
,都来自<memory>
头:
// The Dynamic Student, version 2 -- using smart pointer.
// "Prompt the user for student's first name, a last name, and A - number
// (ID), and then dynamically allocate a `Student` object with these values."
#include <assert.h> // assert
#include <iostream> // std::cout,std::endl
#include <memory> // std::unique_ptr
#include <string> // std::string
#include <sstream> // std::istringstream
#include <stdexcept> // std::exception, std::runtime_error
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
#define CPP_NO_COPYING_OF( Clazz ) \
Clazz( Clazz const& ); \
Clazz& operator=( Clazz const& )
namespace cpp {
using namespace std;
bool hopefully( bool const c ) { return c; }
bool throwX( string const& s ) { throw runtime_error( s ); }
string lineFromInput()
{
string result;
getline( cin, result )
|| throwX( "lineFromInput: std::getline failed (EOF?)" );
return result;
}
string lineFromInput( string const& prompt )
{
cout << prompt;
return lineFromInput();
}
int intFromInput( string const& prompt )
{
istringstream stream( lineFromInput( prompt ) );
int result;
stream >> result
|| throwX( "intFromInput: input line was not a valid number spec" );
return result;
}
} // namespace cpp
namespace blah {
using namespace std;
using namespace cpp;
struct Student
{
CPP_NO_COPYING_OF( Student );
int const id;
string const firstName;
string const lastName;
Student(
int const _id,
string const _firstName,
string const _lastName
)
: id( _id ), firstName( _firstName ), lastName( _lastName )
{}
};
unique_ptr<Student> studentFromInput()
{
cout << "It's -- the Dynamic Student program!" << endl;
string const firstName = lineFromInput( "First name, please? " );
hopefully( firstName != "" )
|| throwX( "Sorry, the first name can't be nothing." );
string const lastName = lineFromInput( "Last name, please? " );
hopefully( lastName != "" )
|| throwX( "Sorry, the last name can't be nothing." );
int const id = intFromInput( "And the student id is...? " );
hopefully( id > 0 )
|| throwX( "Sorry, the id can't be negative or zero." );
return unique_ptr<Student>( new Student( id, firstName, lastName ) );
}
} // namespace blah
void cppMain()
{
using namespace blah;
unique_ptr<Student> const pStudent = studentFromInput();
// Use the student object, e.g.
cout
<< "The student is "
<< pStudent->firstName << " " << pStudent->lastName
<< ", with id " << pStudent->id << "."
<< endl;
}
int main()
{
using namespace std;
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
But, except for the assignment's requirement to use dynamic allocation, a program with the functionality above would be written without any dynamic allocation or smart pointers. The studentFromInput
function would just return a Student
object by value, copying. It is almost a paradox, but modern C++ is very heavily based on copying, and still yields pretty fast programs!
但是,除了分配要求使用动态分配之外,具有上述功能的程序将在没有任何动态分配或智能指针的情况下编写。该studentFromInput
函数只会Student
按值返回一个对象,复制。这几乎是一个悖论,但现代 C++ 在很大程度上基于复制,并且仍然产生相当快的程序!
Of course, under the hood there are a large number of dirty tricks to avoid that the copying actuallyhappens in the machine code.
当然,在引擎盖下有大量肮脏的技巧来避免复制实际上发生在机器代码中。
回答by James Kanze
Why are you using new
? Just declare an instance of the variable:
你为什么使用new
?只需声明变量的一个实例:
Student student1;
Given the definition of Student
, it doesn't look like it has identity,
and it is certainly copyable, so you should probably never new
it.
鉴于 的定义Student
,它看起来没有身份,而且它肯定是可复制的,因此您可能永远不应该使用new
它。
(I'd also provide it with a constructor, so that it can be initialized correctly from the moment it is defined.)
(我还会为它提供一个构造函数,以便从它被定义的那一刻起就可以正确地初始化它。)
回答by Jonathan Grynspan
struct
goes before the name of the structure it defines. :)
struct
在它定义的结构名称之前。:)
What is the error you're seeing when you try new Student
? Why doesn't it work?
您在尝试时看到的错误是new Student
什么?为什么不起作用?
回答by Mike Corcoran
new returns a pointer to an object... so you'd want
new 返回一个指向对象的指针......所以你会想要
struct Student* student1 = new Student;
回答by Ade YU
The new
statement returns a pointer to the new
ed instance. So you need to defined the student1
as a pointer.
该new
语句返回一个指向new
ed 实例的指针。所以你需要将 定义student1
为一个指针。
struct Student * student1 = new Student;