CS374: Programming Language Principles - Modern Language Features
Activity Goals
The goals of this activity are:
- To utilize modern language features for working with memory
- To explain the concept of scope
- To explain the purpose of object references
- To time and compare different architectural approaches
The Activity
Directions
Consider the activity models and answer the questions provided. First reflect on these questions on your own briefly, before discussing and comparing your thoughts with your group. Appoint one member of your group to discuss your findings with the class, and the rest of the group should help that member prepare their response. Answer each question individually from the activity, and compare with your group to prepare for our whole-class discussion. After class, think about the questions in the reflective prompt and respond to those individually in your notebook. Report out on areas of disagreement or items for which you and your group identified alternative approaches. Write down and report out questions you encountered along the way for group discussion.
Model 1: C++ Unique Pointers
Questions
- What does this code do?
- What does this code have in common with traditional pointers? What would you have to do differently if you were creating the pointers yourself?
- What do you think
std::move
does?
- What benefits does
std::unique_ptr
provide?
Model 2: C++ Shared Pointers
Questions
- What is the purpose of the extra curly braces inside
main
?
- When
resPtr1
goes out of scope, why is the underlying memory still accessible?
- In your own words, what is the benefit of a
std::shared_ptr
?
Model 3: Vectors and the C++ Standard Template Library
Questions
- What do you think the
auto
type means? How do you think it works?
- Why is
anotherWidgetPtr
still accessible after removing it from the vector
?
Model 4: C++ Constant Expressions
Questions
- Try this code for various values of
n
and k
. Which program is faster?
- What do you notice when compiling this program? Why do you think this is? What is the compromise?
- What, in your own words, does
constexpr
do?
- What do you think the compiler flag
constexpr-steps
means?
Smart Pointer Examples: Before and After
Example 1: Using unique_ptr
instead of Raw Pointers
Before: Raw Pointers |
After: unique_ptr |
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
void say_hello() const { std::cout << "Hello from Resource\n"; }
};
void raw_pointer_example() {
Resource* res = new Resource();
res->say_hello();
// Simulate transferring ownership (forgetting to delete might cause a memory leak)
Resource* res2 = res;
res = nullptr;
// Resource cleanup
delete res2; // If we forget this, it causes a memory leak.
}
int main() {
raw_pointer_example();
return 0;
}
|
#include <iostream>
#include <memory> // For std::unique_ptr
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
void say_hello() const { std::cout << "Hello from Resource\n"; }
};
void unique_pointer_example() {
std::unique_ptr<Resource> res = std::make_unique<Resource>();
res->say_hello();
// Transferring ownership with std::move
std::unique_ptr<Resource> res2 = std::move(res);
// No need to manually delete, as unique_ptr handles this automatically
// Resource will be destroyed when res2 goes out of scope
}
int main() {
unique_pointer_example();
return 0;
}
|
Example 2: Using shared_ptr
instead of Raw Pointers
Before: Raw Pointers |
After: shared_ptr |
#include <iostream>
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
void say_hello() const { std::cout << "Hello from Resource\n"; }
};
void raw_pointer_shared_example() {
Resource* res = new Resource();
// Multiple "owners" of the same resource
Resource* res1 = res;
Resource* res2 = res;
res1->say_hello();
res2->say_hello();
// Manually managing cleanup
delete res1; // Deleting res1 here makes res2 a dangling pointer
// delete res2; // If uncommented, this would cause undefined behavior (double delete)
}
int main() {
raw_pointer_shared_example();
return 0;
}
|
#include <iostream>
#include <memory> // For std::shared_ptr
class Resource {
public:
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource destroyed\n"; }
void say_hello() const { std::cout << "Hello from Resource\n"; }
};
void shared_pointer_example() {
std::shared_ptr<Resource> res = std::make_shared<Resource>();
// Multiple shared_ptr instances share ownership of the same resource
std::shared_ptr<Resource> res1 = res;
std::shared_ptr<Resource> res2 = res;
res1->say_hello();
res2->say_hello();
// No need to manually delete; the resource is automatically deleted
// when the last shared_ptr (res, res1, or res2) goes out of scope
}
int main() {
shared_pointer_example();
return 0;
}
|
Submission
I encourage you to submit your answers to the questions (and ask your own questions!) using the Class Activity Questions discussion board. You may also respond to questions or comments made by others, or ask follow-up questions there. Answer any reflective prompt questions in the Reflective Journal section of your OneNote Classroom personal section. You can find the link to the class notebook on the syllabus.