Tinker AI
Read reviews

Outcome

Project ongoing; Cursor was useful for ~25% of code but produced unsafe suggestions on memory-management tasks

6 min read

I’ve been working on a small 2D game using a custom C++ engine. The engine is mostly mine; the game logic has a small contribution from Cursor. Eight weeks in, the experience has been instructive — clear strengths and clear weaknesses, with the weaknesses being more dangerous than I expected.

The setup

The project:

  • Custom 2D game engine (mostly C++17)
  • SDL2 for windowing and input
  • Custom rendering layer over OpenGL 3.3
  • Lua scripting for game logic
  • About 25k lines of C++ so far

This is a hobby project; I’m the only developer. Iteration speed matters more than rigorous code review.

Where Cursor helped

Several categories of work benefited from AI assistance:

Game logic in Lua. Lua scripts for entity behaviors, level loading, UI scripting. Cursor’s Lua suggestions were generally good — Lua is well-trained.

Algorithm scaffolding. Pathfinding, tilemap collision, sprite animation. Cursor produced reasonable starting implementations that I’d refine.

File I/O and asset loading. Reading config files, loading textures, parsing tilemap formats. Standard patterns; Cursor handled well.

Mathematical utilities. Vector math, matrix operations, easing functions. Standard math is well-trained.

Test harness code. A small test suite exercising the engine’s deterministic parts. Cursor wrote workable tests.

For these, the productivity gain was substantial — perhaps 40-50% of typing for these specific tasks.

Where Cursor was unsafe

A few categories where suggestions were dangerous:

Memory ownership. C++ has no garbage collector; ownership matters. Cursor’s suggestions sometimes created lifetime issues — returning references to local variables, double-frees, missing destructors. I caught most in review, but some only showed up at runtime.

A specific instance: Cursor suggested a function that returned a const char* from a local std::string. The returned pointer was dangling. The bug only manifested under specific call patterns; debugging took an hour.

Manual memory management. When working with raw new and delete, Cursor’s suggestions sometimes had matching issues — new[] with delete, or vice versa. Subtle but UB-causing.

Template metaprogramming. When I was writing template-heavy code, Cursor’s suggestions were syntactically valid but often had subtle semantic issues — wrong SFINAE patterns, wrong constraint ordering, missing partial specializations.

Reference vs. value semantics. Decisions about pass-by-value vs. pass-by-reference vs. pass-by-rvalue-reference are tricky. Cursor’s defaults didn’t always match what I wanted, sometimes copying when it should have moved.

A pattern I came to use

After a few unsafe suggestions, I developed a pattern: never accept Cursor’s C++ suggestions on first read. Always:

  1. Read the suggestion line by line
  2. Specifically check ownership (who owns this? who deletes? when?)
  3. Check lifetime (does this reference outlive the referent?)
  4. Check exception safety (what happens if this throws?)
  5. Check threading (any data this touches concurrent?)

These five checks caught most of the unsafe suggestions. The discipline of running through them on every Cursor suggestion was tedious but necessary.

For higher-level languages (TypeScript, Python), this discipline is less necessary because the runtime handles many of these concerns. C++ exposes them all.

The ASAN/UBSAN feedback loop

A useful discovery: running with AddressSanitizer (ASAN) and UndefinedBehaviorSanitizer (UBSAN) caught many of Cursor’s mistakes that I’d missed in review.

The cycle:

  1. Cursor suggests code
  2. I review and accept
  3. Build with ASAN/UBSAN enabled
  4. Run tests
  5. Sanitizer catches use-after-free, integer overflow, signed/unsigned mismatch, etc.
  6. Fix the suggestion

This is the safety net for C++ AI work. Without it, the unsafe suggestions ship and bite later. With it, the sanitizers catch most issues before they’re problems.

The cost: builds are slower with sanitizers (2-3x slower). For development, that’s tolerable. For production builds, sanitizers are off.

What Cursor doesn’t catch

The sanitizers don’t catch everything. Specific issues that get past:

Logic bugs. Code that compiles, runs, sanitizes clean, but does the wrong thing. These are caught only by tests.

Performance issues. Code that’s correct but slow. Cursor’s suggestions are sometimes O(n²) when O(n) is possible.

API misuse. Using SDL or OpenGL APIs in ways that “work” but aren’t best practice. The sanitizers don’t know about API conventions.

Cache-unfriendly memory layouts. For game engines, data layout matters. Cursor’s suggestions tend toward “make it work” rather than “make it fast.” For hot paths, the suggestions need rework.

For these, manual review and profiling remain essential.

Comparison to Rust

I’ve also used Cursor on Rust projects. The Rust experience is interestingly different. The compiler catches many of the issues that Cursor produces in C++ — borrowing errors, lifetime mismatches, ownership issues. The same Cursor suggestion that’s dangerous in C++ would fail to compile in Rust.

This means Cursor + Rust is safer than Cursor + C++ in a specific way: the type system serves as a check on AI mistakes that C++‘s lacks.

For new game engine work, this is a real argument for Rust over C++. The AI tooling productivity gap (Rust’s borrow checker can frustrate the AI) is offset by the safety gain.

For my project, switching is too expensive. For someone starting fresh, I’d recommend Rust + AI over C++ + AI on safety grounds alone.

The hobby-project context

Some context: this is a hobby project. The standards I hold are different from production work. For a real game ship to a commercial audience, I’d:

  • Be more rigorous about code review
  • Run sanitizers on every CI build
  • Have a fuzz testing harness
  • Have actual code review from another engineer

For my hobby project, “I tested it and it works” is mostly enough. The AI’s unsafe suggestions cost me a few extra hours of debugging that I would have avoided with manual implementation. Not a great tradeoff but tolerable for a hobby.

For production, I’d be more cautious about AI assistance on memory-management code. The cost of a UB bug in production is higher than the productivity gain of AI suggestions.

What I’d recommend

For C++ developers considering AI tooling:

Use it for non-memory-management code. Algorithms, math, parsing, string manipulation. Lower risk; clear benefit.

Be skeptical on memory-management code. Always review for ownership, lifetime, exception safety. Don’t accept on visual plausibility.

Run sanitizers in development. ASAN/UBSAN catch many of the issues AI suggestions introduce. The performance cost is acceptable for development.

Consider switching to Rust. Especially for new projects. The AI tooling experience is not as smooth, but the compiler’s safety checks compensate for AI mistakes.

Don’t use AI for security-critical code. Memory management bugs in security contexts have catastrophic outcomes. Manual implementation is the right choice.

Closing observation

C++ + AI is workable for non-critical work with discipline. It’s not workable for high-stakes code. The unsafe suggestions are a real risk, mitigated only by careful review and runtime checking.

This isn’t a Cursor failure. The same patterns appear in Cline, Aider, and other tools. C++‘s complexity exposes the limits of AI generation. For now, C++ remains a domain where AI is a productivity assist, not a productivity transformation.

The trajectory may improve. Models trained more deeply on C++ idioms, with better awareness of UB and ownership semantics, would help. None exist yet. For now, calibrated expectations and disciplined review are the answer.